Merge branch 'develop' into sunny/gov-bft-time
This commit is contained in:
commit
72b3a45778
|
@ -415,12 +415,12 @@
|
|||
version = "v0.12.0-rc0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:d4a15d404afbf591e8be16fcda7f5ac87948d5c7531f9d909fd84cc730ab16e2"
|
||||
digest = "1:e99ef92d64f2391efbbfb15310df635f96247532bbac2676ea43e466d706401d"
|
||||
name = "github.com/tendermint/iavl"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "35f66e53d9b01e83b30de68b931f54b2477a94c9"
|
||||
version = "v0.9.2"
|
||||
revision = "e5726c0066ccdd299a2ec9262f93c7896cdfcd87"
|
||||
version = "v0.10.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4f15e95fe3888cc75dd34f407d6394cbc7fd3ff24920851b92b295f6a8b556e6"
|
||||
|
@ -552,7 +552,7 @@
|
|||
"unix",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "11551d06cbcc94edc80a0facaccbda56473c19c1"
|
||||
revision = "4ea2f632f6e912459fe60b26b1749377f0d889d5"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18"
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
|
||||
[[override]]
|
||||
name = "github.com/tendermint/iavl"
|
||||
version = "=v0.9.2"
|
||||
version = "=v0.10.0"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/tendermint/tendermint"
|
||||
|
|
13
Makefile
13
Makefile
|
@ -157,12 +157,23 @@ test_sim_gaia_nondeterminism:
|
|||
|
||||
test_sim_gaia_fast:
|
||||
@echo "Running quick Gaia simulation. This may take several minutes..."
|
||||
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=50 -v -timeout 24h
|
||||
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=150 -v -timeout 24h
|
||||
|
||||
test_sim_gaia_slow:
|
||||
@echo "Running full Gaia simulation. This may take awhile!"
|
||||
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=1000 -SimulationVerbose=true -v -timeout 24h
|
||||
|
||||
SIM_NUM_BLOCKS ?= 210
|
||||
SIM_BLOCK_SIZE ?= 200
|
||||
SIM_COMMIT ?= true
|
||||
test_sim_gaia_benchmark:
|
||||
@echo "Running Gaia benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!"
|
||||
@go test -benchmem -run=^$$ github.com/cosmos/cosmos-sdk/cmd/gaia/app -bench ^BenchmarkFullGaiaSimulation$$ -SimulationEnabled=true -SimulationNumBlocks=$(SIM_NUM_BLOCKS) -SimulationBlockSize=$(SIM_BLOCK_SIZE) -SimulationCommit=$(SIM_COMMIT) -timeout 24h
|
||||
|
||||
test_sim_gaia_profile:
|
||||
@echo "Running Gaia benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!"
|
||||
@go test -benchmem -run=^$$ github.com/cosmos/cosmos-sdk/cmd/gaia/app -bench ^BenchmarkFullGaiaSimulation$$ -SimulationEnabled=true -SimulationNumBlocks=$(SIM_NUM_BLOCKS) -SimulationBlockSize=$(SIM_BLOCK_SIZE) -SimulationCommit=$(SIM_COMMIT) -timeout 24h -cpuprofile cpu.out -memprofile mem.out
|
||||
|
||||
test_cover:
|
||||
@bash tests/test_cover.sh
|
||||
|
||||
|
|
57
PENDING.md
57
PENDING.md
|
@ -8,34 +8,36 @@ BREAKING CHANGES
|
|||
* Gaia CLI (`gaiacli`)
|
||||
* [x/stake] Validator.Owner renamed to Validator.Operator
|
||||
* [cli] unsafe_reset_all, show_validator, and show_node_id have been renamed to unsafe-reset-all, show-validator, and show-node-id
|
||||
* [cli] \#1983 --print-response now defaults to true in commands that create and send a transaction
|
||||
* [cli] \#1983 you can now pass --pubkey or --address to gaiacli keys show to return a plaintext representation of the key's address or public key for use with other commands
|
||||
* [cli] \#2061 changed proposalID in governance REST endpoints to proposal-id
|
||||
* [cli] \#2014 `gaiacli advanced` no longer exists - to access `ibc`, `rest-server`, and `validator-set` commands use `gaiacli ibc`, `gaiacli rest-server`, and `gaiacli tendermint`, respectively
|
||||
* [cli] [\#1983](https://github.com/cosmos/cosmos-sdk/issues/1983) --print-response now defaults to true in commands that create and send a transaction
|
||||
* [cli] [\#1983](https://github.com/cosmos/cosmos-sdk/issues/1983) you can now pass --pubkey or --address to gaiacli keys show to return a plaintext representation of the key's address or public key for use with other commands
|
||||
* [cli] [\#2061](https://github.com/cosmos/cosmos-sdk/issues/2061) changed proposalID in governance REST endpoints to proposal-id
|
||||
* [cli] [\#2014](https://github.com/cosmos/cosmos-sdk/issues/2014) `gaiacli advanced` no longer exists - to access `ibc`, `rest-server`, and `validator-set` commands use `gaiacli ibc`, `gaiacli rest-server`, and `gaiacli tendermint`, respectively
|
||||
* [makefile] `get_vendor_deps` no longer updates lock file it just updates vendor directory. Use `update_vendor_deps` to update the lock file. [#2152](https://github.com/cosmos/cosmos-sdk/pull/2152)
|
||||
* [cli] \#2190 `gaiacli init --gen-txs` is now `gaiacli init --with-txs` to reduce confusion
|
||||
* \#2040 All commands that utilize a validator's address must now use the new
|
||||
* [cli] [\#2190](https://github.com/cosmos/cosmos-sdk/issues/2190) `gaiacli init --gen-txs` is now `gaiacli init --with-txs` to reduce confusion
|
||||
* [\#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
|
||||
now use a new bech32 prefix, `cosmoscons`.
|
||||
|
||||
* Gaia
|
||||
* Make the transient store key use a distinct store key. [#2013](https://github.com/cosmos/cosmos-sdk/pull/2013)
|
||||
* [x/stake] \#1901 Validator type's Owner field renamed to Operator; Validator's GetOwner() renamed accordingly to comply with the SDK's Validator interface.
|
||||
* [x/stake] [\#1901](https://github.com/cosmos/cosmos-sdk/issues/1901) Validator type's Owner field renamed to Operator; Validator's GetOwner() renamed accordingly to comply with the SDK's Validator interface.
|
||||
* [docs] [#2001](https://github.com/cosmos/cosmos-sdk/pull/2001) Update slashing spec for slashing period
|
||||
* [x/stake, x/slashing] [#1305](https://github.com/cosmos/cosmos-sdk/issues/1305) - Rename "revoked" to "jailed"
|
||||
* [x/stake] [#1676] Revoked and jailed validators put into the unbonding state
|
||||
* [x/stake] [#1877] Redelegations/unbonding-delegation from unbonding validator have reduced time
|
||||
* [x/stake] \#2040 Validator operator type has now changed to `sdk.ValAddress`
|
||||
* [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
|
||||
addresses, `cosmosconspub` and `cosmoscons` respectively.
|
||||
* [x/gov] \#2195 Made governance use BFT Time instead of Block Heights for deposit and voting periods.
|
||||
|
||||
* SDK
|
||||
* [core] \#1807 Switch from use of rational to decimal
|
||||
* [types] \#1901 Validator interface's GetOwner() renamed to GetOperator()
|
||||
* [core] [\#1807](https://github.com/cosmos/cosmos-sdk/issues/1807) Switch from use of rational to decimal
|
||||
* [types] [\#1901](https://github.com/cosmos/cosmos-sdk/issues/1901) Validator interface's GetOwner() renamed to GetOperator()
|
||||
* [x/slashing] [#2122](https://github.com/cosmos/cosmos-sdk/pull/2122) - Implement slashing period
|
||||
* [types] \#2119 Parsed error messages and ABCI log errors to make them more human readable.
|
||||
* [types] [\#2119](https://github.com/cosmos/cosmos-sdk/issues/2119) Parsed error messages and ABCI log errors to make them more human readable.
|
||||
* [simulation] Rename TestAndRunTx to Operation [#2153](https://github.com/cosmos/cosmos-sdk/pull/2153)
|
||||
* [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
|
||||
|
||||
|
@ -44,23 +46,26 @@ FEATURES
|
|||
|
||||
* Gaia REST API (`gaiacli advanced rest-server`)
|
||||
* [lcd] Endpoints to query staking pool and params
|
||||
* [lcd] \#2110 Add support for `simulate=true` requests query argument to endpoints that send txs to run simulations of transactions
|
||||
* [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`)
|
||||
* [cli] Cmds to query staking pool and params
|
||||
* [gov][cli] #2062 added `--proposal` flag to `submit-proposal` that allows a JSON file containing a proposal to be passed in
|
||||
* \#2040 Add `--bech` to `gaiacli keys show` and respective REST endpoint to
|
||||
* [\#2040](https://github.com/cosmos/cosmos-sdk/issues/2040) Add `--bech` to `gaiacli keys show` and respective REST endpoint to
|
||||
provide desired Bech32 prefix encoding
|
||||
* [cli] \#2047 Setting the --gas flag value to 0 triggers a simulation of the tx before the actual execution. The gas estimate obtained via the simulation will be used as gas limit in the actual execution.
|
||||
* [cli] \#2047 The --gas-adjustment flag can be used to adjust the estimate obtained via the simulation triggered by --gas=0.
|
||||
* [cli] \#2110 Add --dry-run flag to perform a simulation of a transaction without broadcasting it. The --gas flag is ignored as gas would be automatically estimated.
|
||||
* [cli] [\#2047](https://github.com/cosmos/cosmos-sdk/issues/2047) 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) The --gas-adjustment flag can be used to adjust the estimate obtained via the simulation triggered by --gas=0.
|
||||
* [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
|
||||
* [cli] #2170 added ability to show the node's address via `gaiad tendermint show-address`
|
||||
|
||||
* SDK
|
||||
* [querier] added custom querier functionality, so ABCI query requests can be handled by keepers
|
||||
* [simulation] \#1924 allow operations to specify future operations
|
||||
* [simulation] [\#1924](https://github.com/cosmos/cosmos-sdk/issues/1924) allow operations to specify future operations
|
||||
* [simulation] [\#1924](https://github.com/cosmos/cosmos-sdk/issues/1924) Add benchmarking capabilities, with makefile commands "test_sim_gaia_benchmark, test_sim_gaia_profile"
|
||||
|
||||
* Tendermint
|
||||
|
||||
|
@ -70,7 +75,7 @@ IMPROVEMENTS
|
|||
* [tools] Added ansible script to enable process core dumps
|
||||
|
||||
* Gaia REST API (`gaiacli advanced rest-server`)
|
||||
* [x/stake] \#2000 Added tests for new staking endpoints
|
||||
* [x/stake] [\#2000](https://github.com/cosmos/cosmos-sdk/issues/2000) Added tests for new staking endpoints
|
||||
|
||||
* Gaia CLI (`gaiacli`)
|
||||
* [cli] #2060 removed `--select` from `block` command
|
||||
|
@ -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/auth] Signature verification's gas cost now accounts for pubkey type. [#2046](https://github.com/tendermint/tendermint/pull/2046)
|
||||
* [x/stake] [x/slashing] Ensure delegation invariants to jailed validators [#1883](https://github.com/cosmos/cosmos-sdk/issues/1883).
|
||||
|
||||
* [x/stake] Improve speed of GetValidator, which was shown to be a performance bottleneck. [#2046](https://github.com/tendermint/tendermint/pull/2200)
|
||||
* SDK
|
||||
* [tools] Make get_vendor_deps deletes `.vendor-new` directories, in case scratch files are present.
|
||||
* [cli] \#1632 Add integration tests to ensure `basecoind init && basecoind` start sequences run successfully for both `democoin` and `basecoin` examples.
|
||||
* [spec] Added simple piggy bank distribution spec
|
||||
* [cli] [\#1632](https://github.com/cosmos/cosmos-sdk/issues/1632) Add integration tests to ensure `basecoind init && basecoind` start sequences run successfully for both `democoin` and `basecoin` examples.
|
||||
* [store] Speedup IAVL iteration, and consequently everything that requires IAVL iteration. [#2143](https://github.com/cosmos/cosmos-sdk/issues/2143)
|
||||
* [store] \#1952 Update IAVL dependency to v0.10.0
|
||||
* [simulation] Make timestamps randomized [#2153](https://github.com/cosmos/cosmos-sdk/pull/2153)
|
||||
|
||||
* Tendermint
|
||||
|
@ -94,15 +101,15 @@ BUG FIXES
|
|||
* Gaia REST API (`gaiacli advanced rest-server`)
|
||||
|
||||
* Gaia CLI (`gaiacli`)
|
||||
* [cli] \#1997 Handle panics gracefully when `gaiacli stake {delegation,unbond}` fail to unmarshal delegation.
|
||||
* [cli] [\#1997](https://github.com/cosmos/cosmos-sdk/issues/1997) Handle panics gracefully when `gaiacli stake {delegation,unbond}` fail to unmarshal delegation.
|
||||
|
||||
* Gaia
|
||||
|
||||
* SDK
|
||||
* \#1988 Make us compile on OpenBSD (disable ledger) [#1988] (https://github.com/cosmos/cosmos-sdk/issues/1988)
|
||||
* \#2105 Fix DB Iterator leak, which may leak a go routine.
|
||||
* [ledger] \#2064 Fix inability to sign and send transactions via the LCD by
|
||||
* [\#1988](https://github.com/cosmos/cosmos-sdk/issues/1988) Make us compile on OpenBSD (disable ledger) [#1988] (https://github.com/cosmos/cosmos-sdk/issues/1988)
|
||||
* [\#2105](https://github.com/cosmos/cosmos-sdk/issues/2105) Fix DB Iterator leak, which may leak a go routine.
|
||||
* [ledger] [\#2064](https://github.com/cosmos/cosmos-sdk/issues/2064) Fix inability to sign and send transactions via the LCD by
|
||||
loading a Ledger device at runtime.
|
||||
* \#2158 Fix non-deterministic ordering of validator iteration when slashing in `gov EndBlocker`
|
||||
* [\#2158](https://github.com/cosmos/cosmos-sdk/issues/2158) Fix non-deterministic ordering of validator iteration when slashing in `gov EndBlocker`
|
||||
|
||||
* Tendermint
|
||||
|
|
|
@ -345,6 +345,7 @@ func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) (res a
|
|||
return queryable.Query(req)
|
||||
}
|
||||
|
||||
// nolint: unparam
|
||||
func handleQueryP2P(app *BaseApp, path []string, req abci.RequestQuery) (res abci.ResponseQuery) {
|
||||
// "/p2p" prefix for p2p queries
|
||||
if len(path) >= 4 {
|
||||
|
|
|
@ -626,12 +626,12 @@ func TestSimulateTx(t *testing.T) {
|
|||
// simulate a message, check gas reported
|
||||
result := app.Simulate(tx)
|
||||
require.True(t, result.IsOK(), result.Log)
|
||||
require.Equal(t, int64(gasConsumed), result.GasUsed)
|
||||
require.Equal(t, gasConsumed, result.GasUsed)
|
||||
|
||||
// simulate again, same result
|
||||
result = app.Simulate(tx)
|
||||
require.True(t, result.IsOK(), result.Log)
|
||||
require.Equal(t, int64(gasConsumed), result.GasUsed)
|
||||
require.Equal(t, gasConsumed, result.GasUsed)
|
||||
|
||||
// simulate by calling Query with encoded tx
|
||||
txBytes, err := codec.MarshalBinary(tx)
|
||||
|
|
|
@ -26,12 +26,6 @@ func (app *BaseApp) SetCMS(cms store.CommitMultiStore) {
|
|||
}
|
||||
app.cms = cms
|
||||
}
|
||||
func (app *BaseApp) SetTxDecoder(txDecoder sdk.TxDecoder) {
|
||||
if app.sealed {
|
||||
panic("SetTxDecoder() on sealed BaseApp")
|
||||
}
|
||||
app.txDecoder = txDecoder
|
||||
}
|
||||
func (app *BaseApp) SetInitChainer(initChainer sdk.InitChainer) {
|
||||
if app.sealed {
|
||||
panic("SetInitChainer() on sealed BaseApp")
|
||||
|
|
|
@ -3,10 +3,11 @@ package context
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"io"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
|
||||
|
@ -38,6 +39,7 @@ type CLIContext struct {
|
|||
PrintResponse bool
|
||||
Certifier tmlite.Certifier
|
||||
DryRun bool
|
||||
GenerateOnly bool
|
||||
}
|
||||
|
||||
// NewCLIContext returns a new initialized CLIContext with parameters from the
|
||||
|
@ -65,6 +67,7 @@ func NewCLIContext() CLIContext {
|
|||
PrintResponse: viper.GetBool(client.FlagPrintResponse),
|
||||
Certifier: createCertifier(),
|
||||
DryRun: viper.GetBool(client.FlagDryRun),
|
||||
GenerateOnly: viper.GetBool(client.FlagGenerateOnly),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@ import (
|
|||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/store"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
@ -17,7 +19,6 @@ import (
|
|||
tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
|
||||
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GetNode returns an RPC client. If the context's client is not defined, an
|
||||
|
@ -323,6 +324,7 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, err erro
|
|||
}
|
||||
|
||||
// verifyProof perform response proof verification
|
||||
// nolint: unparam
|
||||
func (ctx CLIContext) verifyProof(path string, resp abci.ResponseQuery) error {
|
||||
|
||||
if ctx.Certifier == nil {
|
||||
|
|
|
@ -27,6 +27,7 @@ const (
|
|||
FlagJson = "json"
|
||||
FlagPrintResponse = "print-response"
|
||||
FlagDryRun = "dry-run"
|
||||
FlagGenerateOnly = "generate-only"
|
||||
)
|
||||
|
||||
// LineBreak can be included in a command list to provide a blank line
|
||||
|
@ -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(FlagTrustNode, true, "Don't verify proofs for query responses")
|
||||
c.Flags().Bool(FlagDryRun, false, "ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it")
|
||||
c.Flags().Bool(FlagGenerateOnly, false, "build an unsigned transaction and write it to STDOUT")
|
||||
}
|
||||
return cmds
|
||||
}
|
||||
|
|
|
@ -313,6 +313,22 @@ func TestIBCTransfer(t *testing.T) {
|
|||
// 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) {
|
||||
name, password := "test", "1234567890"
|
||||
addr, seed := CreateAddr(t, "test", password, GetKeyBase(t))
|
||||
|
|
|
@ -3,11 +3,17 @@ package utils
|
|||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
auth "github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
|
||||
)
|
||||
|
||||
const (
|
||||
queryArgDryRun = "simulate"
|
||||
queryArgDryRun = "simulate"
|
||||
queryArgGenerateOnly = "generate_only"
|
||||
)
|
||||
|
||||
// WriteErrorResponse prepares and writes a HTTP error
|
||||
|
@ -26,9 +32,10 @@ func WriteSimulationResponse(w http.ResponseWriter, gas int64) {
|
|||
|
||||
// HasDryRunArg returns true if the request's URL query contains
|
||||
// the dry run argument and its value is set to "true".
|
||||
func HasDryRunArg(r *http.Request) bool {
|
||||
return r.URL.Query().Get(queryArgDryRun) == "true"
|
||||
}
|
||||
func HasDryRunArg(r *http.Request) bool { return urlQueryHasArg(r.URL, queryArgDryRun) }
|
||||
|
||||
// HasGenerateOnlyArg returns whether a URL's query "generate-only" parameter is set to "true".
|
||||
func HasGenerateOnlyArg(r *http.Request) bool { return urlQueryHasArg(r.URL, queryArgGenerateOnly) }
|
||||
|
||||
// ParseFloat64OrReturnBadRequest converts s to a float64 value. It returns a default
|
||||
// value if the string is empty. Write
|
||||
|
@ -43,3 +50,21 @@ func ParseFloat64OrReturnBadRequest(w http.ResponseWriter, s string, defaultIfEm
|
|||
}
|
||||
return n, true
|
||||
}
|
||||
|
||||
// WriteGenerateStdTxResponse writes response for the generate_only mode.
|
||||
func WriteGenerateStdTxResponse(w http.ResponseWriter, txCtx authctx.TxContext, msgs []sdk.Msg) {
|
||||
stdMsg, err := txCtx.Build(msgs)
|
||||
if err != nil {
|
||||
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
output, err := txCtx.Codec.MarshalJSON(auth.NewStdTx(stdMsg.Msgs, stdMsg.Fee, nil, stdMsg.Memo))
|
||||
if err != nil {
|
||||
WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
w.Write(output)
|
||||
return
|
||||
}
|
||||
|
||||
func urlQueryHasArg(url *url.URL, arg string) bool { return url.Query().Get(arg) == "true" }
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||
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"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/tendermint/libs/common"
|
||||
|
@ -28,7 +29,7 @@ func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg)
|
|||
if err != nil {
|
||||
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 {
|
||||
return nil
|
||||
|
@ -85,6 +86,19 @@ func CalculateGas(queryFunc func(string, common.HexBytes) ([]byte, error), cdc *
|
|||
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 {
|
||||
return int64(adjustment * float64(estimate))
|
||||
}
|
||||
|
@ -128,3 +142,24 @@ func prepareTxContext(txCtx authctx.TxContext, cliCtx context.CLIContext) (authc
|
|||
}
|
||||
return txCtx, nil
|
||||
}
|
||||
|
||||
// buildUnsignedStdTx builds a StdTx as per the parameters passed in the
|
||||
// contexts. Gas is automatically estimated if gas wanted is set to 0.
|
||||
func buildUnsignedStdTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) (stdTx auth.StdTx, err error) {
|
||||
txCtx, err = prepareTxContext(txCtx, cliCtx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if txCtx.Gas == 0 {
|
||||
txCtx, err = EnrichCtxWithGas(txCtx, cliCtx, cliCtx.FromAddressName, msgs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "estimated gas = %v\n", txCtx.Gas)
|
||||
}
|
||||
stdSignMsg, err := txCtx.Build(msgs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return auth.NewStdTx(stdSignMsg.Msgs, stdSignMsg.Fee, nil, stdSignMsg.Memo), nil
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ func resolveProjectPath(remoteProjectPath string) string {
|
|||
return gopath + string(os.PathSeparator) + "src" + string(os.PathSeparator) + remoteProjectPath
|
||||
}
|
||||
|
||||
// nolint: unparam, errcheck
|
||||
func copyBasecoinTemplate(projectName string, projectPath string, remoteProjectPath string) {
|
||||
basecoinProjectPath := resolveProjectPath(remoteBasecoinPath)
|
||||
filepath.Walk(basecoinProjectPath, func(path string, f os.FileInfo, err error) error {
|
||||
|
@ -88,6 +89,7 @@ func copyBasecoinTemplate(projectName string, projectPath string, remoteProjectP
|
|||
})
|
||||
}
|
||||
|
||||
// nolint: errcheck
|
||||
func createGopkg(projectPath string) {
|
||||
// Create gopkg.toml file
|
||||
dependencies := map[string]string{
|
||||
|
@ -111,6 +113,7 @@ func createGopkg(projectPath string) {
|
|||
ioutil.WriteFile(projectPath+"/Gopkg.toml", []byte(contents), os.ModePerm)
|
||||
}
|
||||
|
||||
// nolint: errcheck
|
||||
func createMakefile(projectPath string) {
|
||||
// Create makefile
|
||||
// TODO: Should we use tools/ directory as in Cosmos-SDK to get tools for linting etc.
|
||||
|
|
|
@ -3,7 +3,9 @@ package app
|
|||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -15,6 +17,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
banksim "github.com/cosmos/cosmos-sdk/x/bank/simulation"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation"
|
||||
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
|
||||
slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation"
|
||||
|
@ -28,6 +31,7 @@ var (
|
|||
blockSize int
|
||||
enabled bool
|
||||
verbose bool
|
||||
commit bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -36,6 +40,7 @@ func init() {
|
|||
flag.IntVar(&blockSize, "SimulationBlockSize", 200, "Operations per block")
|
||||
flag.BoolVar(&enabled, "SimulationEnabled", false, "Enable the simulation")
|
||||
flag.BoolVar(&verbose, "SimulationVerbose", false, "Verbose log output")
|
||||
flag.BoolVar(&commit, "SimulationCommit", false, "Have the simulation commit")
|
||||
}
|
||||
|
||||
func appStateFn(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage {
|
||||
|
@ -49,7 +54,7 @@ func appStateFn(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json
|
|||
Coins: coins,
|
||||
})
|
||||
}
|
||||
|
||||
govGenesis := gov.DefaultGenesisState()
|
||||
// Default genesis state
|
||||
stakeGenesis := stake.DefaultGenesisState()
|
||||
var validators []stake.Validator
|
||||
|
@ -73,6 +78,7 @@ func appStateFn(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json
|
|||
genesis := GenesisState{
|
||||
Accounts: genesisAccounts,
|
||||
StakeData: stakeGenesis,
|
||||
GovData: govGenesis,
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if !enabled {
|
||||
t.Skip("Skipping Gaia simulation")
|
||||
|
@ -136,9 +175,11 @@ func TestFullGaiaSimulation(t *testing.T) {
|
|||
invariants(app),
|
||||
numBlocks,
|
||||
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
|
||||
|
@ -148,7 +189,7 @@ func TestAppStateDeterminism(t *testing.T) {
|
|||
t.Skip("Skipping Gaia simulation")
|
||||
}
|
||||
|
||||
numSeeds := 5
|
||||
numSeeds := 3
|
||||
numTimesToRunPerSeed := 5
|
||||
appHashList := make([]json.RawMessage, numTimesToRunPerSeed)
|
||||
|
||||
|
@ -165,10 +206,11 @@ func TestAppStateDeterminism(t *testing.T) {
|
|||
testAndRunTxs(app),
|
||||
[]simulation.RandSetup{},
|
||||
[]simulation.Invariant{},
|
||||
20,
|
||||
20,
|
||||
true,
|
||||
50,
|
||||
100,
|
||||
false,
|
||||
)
|
||||
app.Commit()
|
||||
appHash := app.LastCommitID().Hash
|
||||
appHashList[j] = appHash
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/tendermint/tendermint/crypto"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
|
@ -155,8 +156,18 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
|||
|
||||
initialPool.BondedTokens = initialPool.BondedTokens.Add(sdk.NewDec(1))
|
||||
|
||||
// Test --generate-only
|
||||
success, stdout, stderr := executeWriteRetStdStreams(t, cvStr+" --generate-only", app.DefaultKeyPass)
|
||||
require.True(t, success)
|
||||
require.True(t, success)
|
||||
require.Empty(t, stderr)
|
||||
msg := unmarshalStdTx(t, stdout)
|
||||
require.NotZero(t, msg.Fee.Gas)
|
||||
require.Equal(t, len(msg.Msgs), 1)
|
||||
require.Equal(t, 0, len(msg.GetSignatures()))
|
||||
|
||||
// Test --dry-run
|
||||
success := executeWrite(t, cvStr+" --dry-run", app.DefaultKeyPass)
|
||||
success = executeWrite(t, cvStr+" --dry-run", app.DefaultKeyPass)
|
||||
require.True(t, success)
|
||||
|
||||
executeWrite(t, cvStr, app.DefaultKeyPass)
|
||||
|
@ -222,8 +233,18 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
spStr += fmt.Sprintf(" --title=%s", "Test")
|
||||
spStr += fmt.Sprintf(" --description=%s", "test")
|
||||
|
||||
// Test generate only
|
||||
success, stdout, stderr := executeWriteRetStdStreams(t, spStr+" --generate-only", app.DefaultKeyPass)
|
||||
require.True(t, success)
|
||||
require.True(t, success)
|
||||
require.Empty(t, stderr)
|
||||
msg := unmarshalStdTx(t, stdout)
|
||||
require.NotZero(t, msg.Fee.Gas)
|
||||
require.Equal(t, len(msg.Msgs), 1)
|
||||
require.Equal(t, 0, len(msg.GetSignatures()))
|
||||
|
||||
// Test --dry-run
|
||||
success := executeWrite(t, spStr+" --dry-run", app.DefaultKeyPass)
|
||||
success = executeWrite(t, spStr+" --dry-run", app.DefaultKeyPass)
|
||||
require.True(t, success)
|
||||
|
||||
executeWrite(t, spStr, app.DefaultKeyPass)
|
||||
|
@ -244,6 +265,16 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
depositStr += fmt.Sprintf(" --deposit=%s", "10steak")
|
||||
depositStr += fmt.Sprintf(" --proposal-id=%s", "1")
|
||||
|
||||
// Test generate only
|
||||
success, stdout, stderr = executeWriteRetStdStreams(t, depositStr+" --generate-only", app.DefaultKeyPass)
|
||||
require.True(t, success)
|
||||
require.True(t, success)
|
||||
require.Empty(t, stderr)
|
||||
msg = unmarshalStdTx(t, stdout)
|
||||
require.NotZero(t, msg.Fee.Gas)
|
||||
require.Equal(t, len(msg.Msgs), 1)
|
||||
require.Equal(t, 0, len(msg.GetSignatures()))
|
||||
|
||||
executeWrite(t, depositStr, app.DefaultKeyPass)
|
||||
tests.WaitForNextNBlocksTM(2, port)
|
||||
|
||||
|
@ -258,6 +289,16 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
voteStr += fmt.Sprintf(" --proposal-id=%s", "1")
|
||||
voteStr += fmt.Sprintf(" --option=%s", "Yes")
|
||||
|
||||
// Test generate only
|
||||
success, stdout, stderr = executeWriteRetStdStreams(t, voteStr+" --generate-only", app.DefaultKeyPass)
|
||||
require.True(t, success)
|
||||
require.True(t, success)
|
||||
require.Empty(t, stderr)
|
||||
msg = unmarshalStdTx(t, stdout)
|
||||
require.NotZero(t, msg.Fee.Gas)
|
||||
require.Equal(t, len(msg.Msgs), 1)
|
||||
require.Equal(t, 0, len(msg.GetSignatures()))
|
||||
|
||||
executeWrite(t, voteStr, app.DefaultKeyPass)
|
||||
tests.WaitForNextNBlocksTM(2, port)
|
||||
|
||||
|
@ -291,6 +332,52 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
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
|
||||
|
||||
|
@ -315,6 +402,12 @@ func initializeFixtures(t *testing.T) (chainID, servAddr, port string) {
|
|||
return
|
||||
}
|
||||
|
||||
func unmarshalStdTx(t *testing.T, s string) (stdTx auth.StdTx) {
|
||||
cdc := app.MakeCodec()
|
||||
require.Nil(t, cdc.UnmarshalJSON([]byte(s), &stdTx))
|
||||
return
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________
|
||||
// executors
|
||||
|
||||
|
|
|
@ -224,9 +224,9 @@ func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig []byte, pub t
|
|||
}
|
||||
case offlineInfo:
|
||||
linfo := info.(offlineInfo)
|
||||
fmt.Printf("Bytes to sign:\n%s", msg)
|
||||
fmt.Fprintf(os.Stderr, "Bytes to sign:\n%s", msg)
|
||||
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
|
||||
signed, err := buf.ReadString('\n')
|
||||
if err != nil {
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Please note that this folder is a WIP specification for an advanced fee distribution
|
||||
mechanism which is not set to be implemented.
|
|
@ -0,0 +1,36 @@
|
|||
# End Block
|
||||
|
||||
At each endblock, the fees received are sorted to the proposer, community fund,
|
||||
and global pool. When the validator is the proposer of the round, that
|
||||
validator (and their delegators) receives between 1% and 5% of fee rewards, the
|
||||
reserve tax is then charged, then the remainder is distributed proportionally
|
||||
by voting power to all bonded validators independent of whether they voted
|
||||
(social distribution). Note the social distribution is applied to proposer
|
||||
validator in addition to the proposer reward.
|
||||
|
||||
The amount of proposer reward is calculated from pre-commits Tendermint
|
||||
messages in order to incentivize validators to wait and include additional
|
||||
pre-commits in the block. All provision rewards are added to a provision reward
|
||||
pool which validator holds individually
|
||||
(`ValidatorDistribution.ProvisionsRewardPool`).
|
||||
|
||||
```
|
||||
func SortFees(feesCollected sdk.Coins, global Global, proposer ValidatorDistribution,
|
||||
sumPowerPrecommitValidators, totalBondedTokens, communityTax sdk.Dec)
|
||||
|
||||
feesCollectedDec = MakeDecCoins(feesCollected)
|
||||
proposerReward = feesCollectedDec * (0.01 + 0.04
|
||||
* sumPowerPrecommitValidators / totalBondedTokens)
|
||||
proposer.ProposerPool += proposerReward
|
||||
|
||||
communityFunding = feesCollectedDec * communityTax
|
||||
global.CommunityFund += communityFunding
|
||||
|
||||
poolReceived = feesCollectedDec - proposerReward - communityFunding
|
||||
global.Pool += poolReceived
|
||||
global.EverReceivedPool += poolReceived
|
||||
global.LastReceivedPool = poolReceived
|
||||
|
||||
SetValidatorDistribution(proposer)
|
||||
SetGlobal(global)
|
||||
```
|
|
@ -0,0 +1,54 @@
|
|||
# Distribution
|
||||
|
||||
## Overview
|
||||
|
||||
Collected fees are pooled globally and divided out passively to validators and
|
||||
delegators. Each validator has the opportunity to charge commission to the
|
||||
delegators on the fees collected on behalf of the delegators by the validators.
|
||||
Fees are paid directly into a global fee pool, and validator proposer-reward
|
||||
pool. Due to the nature of passive accounting whenever changes to parameters
|
||||
which affect the rate of fee distribution occurs, withdrawal of fees must also
|
||||
occur when:
|
||||
|
||||
- withdrawing one must withdrawal the maximum amount they are entitled
|
||||
too, leaving nothing in the pool,
|
||||
- bonding, unbonding, or re-delegating tokens to an existing account a
|
||||
full withdrawal of the fees must occur (as the rules for lazy accounting
|
||||
change),
|
||||
- a validator chooses to change the commission on fees, all accumulated
|
||||
commission fees must be simultaneously withdrawn.
|
||||
|
||||
The above scenarios are covered in `triggers.md`.
|
||||
|
||||
The distribution mechanism outlines herein is used to lazily distribute the
|
||||
following between validators and associated delegators:
|
||||
- multi-token fees to be socially distributed,
|
||||
- proposer reward pool,
|
||||
- inflated atom provisions, and
|
||||
- validator commission on all rewards earned by their delegators stake
|
||||
|
||||
Fees are pooled within a global pool, as well as validator specific
|
||||
proposer-reward pools. The mechanisms used allow for validators and delegators
|
||||
to independently and lazily withdrawn their rewards. As a part of the lazy
|
||||
computations adjustment factors must be maintained for each validator and
|
||||
delegator to determine the true proportion of fees in each pool which they are
|
||||
entitled too. Adjustment factors are updated every time a validator or
|
||||
delegator's voting power changes. Validators and delegators must withdraw all
|
||||
fees they are entitled too before they can change their portion of bonded
|
||||
Atoms.
|
||||
|
||||
## Affect on Staking
|
||||
|
||||
|
||||
Charging commission on Atom provisions while also allowing for Atom-provisions
|
||||
to be auto-bonded (distributed directly to the validators bonded stake) is
|
||||
problematic within DPoS. Fundamentally these two mechnisms are mutually
|
||||
exclusive. If there are atoms commissions and auto-bonding Atoms, the portion
|
||||
of Atoms the fee distribution calculation would become very large as the Atom
|
||||
portion for each delegator would change each block making a withdrawal of fees
|
||||
for a delegator require a calculation for every single block since the last
|
||||
withdrawal. In conclusion we can only have atom commission and unbonded atoms
|
||||
provisions, or bonded atom provisions with no Atom commission, and we elect to
|
||||
implement the former. Stakeholders wishing to rebond their provisions may elect
|
||||
to set up a script to periodically withdraw and rebond fees.
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
## State
|
||||
|
||||
### Global
|
||||
|
||||
All globally tracked parameters for distribution are stored within
|
||||
`Global`. Rewards are collected and added to the reward pool and
|
||||
distributed to validators/delegators from here.
|
||||
|
||||
Note that the reward pool holds decimal coins (`DecCoins`) to allow
|
||||
for fractions of coins to be received from operations like inflation.
|
||||
When coins are distributed from the pool they are truncated back to
|
||||
`sdk.Coins` which are non-decimal.
|
||||
|
||||
- Global: `0x00 -> amino(global)`
|
||||
|
||||
```golang
|
||||
// coins with decimal
|
||||
type DecCoins []DecCoin
|
||||
|
||||
type DecCoin struct {
|
||||
Amount sdk.Dec
|
||||
Denom string
|
||||
}
|
||||
|
||||
type Global struct {
|
||||
PrevBondedTokens sdk.Dec // bonded token amount for the global pool on the previous block
|
||||
Adjustment sdk.Dec // global adjustment factor for lazy calculations
|
||||
Pool DecCoins // funds for all validators which have yet to be withdrawn
|
||||
PrevReceivedPool DecCoins // funds added to the pool on the previous block
|
||||
EverReceivedPool DecCoins // total funds ever added to the pool
|
||||
CommunityFund DecCoins // pool for community funds yet to be spent
|
||||
}
|
||||
```
|
||||
|
||||
### Validator Distribution
|
||||
|
||||
Validator distribution information for the relevant validator is updated each time:
|
||||
1. delegation amount to a validator are updated,
|
||||
2. a validator successfully proposes a block and receives a reward,
|
||||
3. any delegator withdraws from a validator, or
|
||||
4. the validator withdraws it's commission.
|
||||
|
||||
- ValidatorDistribution: `0x02 | ValOwnerAddr -> amino(validatorDistribution)`
|
||||
|
||||
```golang
|
||||
type ValidatorDistribution struct {
|
||||
CommissionWithdrawalHeight int64 // last time this validator withdrew commission
|
||||
Adjustment sdk.Dec // global pool adjustment factor
|
||||
ProposerAdjustment DecCoins // proposer pool adjustment factor
|
||||
ProposerPool DecCoins // reward pool collected from being the proposer
|
||||
EverReceivedProposerReward DecCoins // all rewards ever collected from being the proposer
|
||||
PrevReceivedProposerReward DecCoins // previous rewards collected from being the proposer
|
||||
PrevBondedTokens sdk.Dec // bonded token amount on the previous block
|
||||
PrevDelegatorShares sdk.Dec // amount of delegator shares for the validator on the previous block
|
||||
}
|
||||
```
|
||||
|
||||
### Delegation Distribution
|
||||
|
||||
Each delegation holds multiple adjustment factors to specify its entitlement to
|
||||
the rewards from a validator. `AdjustmentPool` is used to passively calculate
|
||||
each bonds entitled fees from the `RewardPool`. `AdjustmentPool` is used to
|
||||
passively calculate each bonds entitled fees from
|
||||
`ValidatorDistribution.ProposerRewardPool`
|
||||
|
||||
- DelegatorDistribution: ` 0x02 | DelegatorAddr | ValOwnerAddr -> amino(delegatorDist)`
|
||||
|
||||
```golang
|
||||
type DelegatorDist struct {
|
||||
WithdrawalHeight int64 // last time this delegation withdrew rewards
|
||||
Adjustment sdk.Dec // fee provisioning adjustment factor
|
||||
AdjustmentProposer DecCoins // proposers pool adjustment factor
|
||||
PrevTokens sdk.Dec // bonded tokens held by the delegation on the previous block
|
||||
PrevShares sdk.Dec // delegator shares held by the delegation on the previous block
|
||||
}
|
||||
```
|
||||
|
||||
### Power Change
|
||||
|
||||
Every instance that the voting power changes, information about the state of
|
||||
the validator set during the change must be recorded as a `PowerChange` for
|
||||
other validators to run through. Each power change is indexed by its block
|
||||
height.
|
||||
|
||||
- PowerChange: `0x03 | amino(Height) -> amino(validatorDist)`
|
||||
|
||||
```golang
|
||||
type PowerChange struct {
|
||||
Height int64 // block height at change
|
||||
ValidatorBondedTokens sdk.Dec // following used to create distribution scenarios
|
||||
ValidatorDelegatorShares sdk.Dec
|
||||
ValidatorDelegatorShareExRate sdk.Dec
|
||||
ValidatorCommission sdk.Dec
|
||||
PoolBondedTokens sdk.Dec
|
||||
Global Global
|
||||
ValDistr ValidatorDistribution
|
||||
DelegationShares sdk.Dec
|
||||
DelDistr DelegatorDistribution
|
||||
}
|
||||
```
|
|
@ -0,0 +1,399 @@
|
|||
# Transactions
|
||||
|
||||
## TxWithdrawDelegation
|
||||
|
||||
When a delegator wishes to withdraw their transaction fees it must send
|
||||
`TxWithdrawDelegation`. Note that parts of this transaction logic are also
|
||||
triggered each with any change in individual delegations, such as an unbond,
|
||||
redelegation, or delegation of additional tokens to a specific validator.
|
||||
|
||||
Each time a withdrawal is made by a recipient the adjustment term must be
|
||||
modified for each block with a change in distributors shares since the time of
|
||||
last withdrawal. This is accomplished by iterating over all relevant
|
||||
`PowerChange`'s stored in distribution state.
|
||||
|
||||
|
||||
```golang
|
||||
type TxWithdrawDelegation struct {
|
||||
delegatorAddr sdk.AccAddress
|
||||
withdrawAddr sdk.AccAddress // address to make the withdrawal to
|
||||
}
|
||||
|
||||
func WithdrawDelegator(delegatorAddr, withdrawAddr sdk.AccAddress)
|
||||
entitlement = GetDelegatorEntitlement(delegatorAddr)
|
||||
AddCoins(withdrawAddr, totalEntitlment.TruncateDecimal())
|
||||
|
||||
func GetDelegatorEntitlement(delegatorAddr sdk.AccAddress) DecCoins
|
||||
|
||||
// compile all the distribution scenarios
|
||||
delegations = GetDelegations(delegatorAddr)
|
||||
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
|
||||
delegation.ValidatorAddr)
|
||||
pcs = GetPowerChanges(DelDistr.WithdrawalHeight)
|
||||
|
||||
// update all adjustment factors for each delegation since last withdrawal
|
||||
for pc = range pcs
|
||||
for delegation = range delegations
|
||||
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
|
||||
delegation.ValidatorAddr)
|
||||
pc.ProcessPowerChangeDelegation(delegation, DelDistr)
|
||||
|
||||
// collect all entitled fees
|
||||
entitlement = 0
|
||||
for delegation = range delegations
|
||||
global = GetGlobal()
|
||||
pool = GetPool()
|
||||
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
|
||||
delegation.ValidatorAddr)
|
||||
ValDistr = GetValidatorDistribution(delegation.ValidatorAddr)
|
||||
validator = GetValidator(delegation.ValidatorAddr)
|
||||
|
||||
scenerio1 = NewDelegationFromGlobalPool(delegation, validator,
|
||||
pool, global, ValDistr, DelDistr)
|
||||
scenerio2 = NewDelegationFromProvisionPool(delegation, validator,
|
||||
ValDistr, DelDistr)
|
||||
entitlement += scenerio1.WithdrawalEntitlement()
|
||||
entitlement += scenerio2.WithdrawalEntitlement()
|
||||
|
||||
return entitlement
|
||||
|
||||
func (pc PowerChange) ProcessPowerChangeDelegation(delegation sdk.Delegation,
|
||||
DelDistr DelegationDistribution)
|
||||
|
||||
// get the historical scenarios
|
||||
scenario1 = pc.DelegationFromGlobalPool(delegation, DelDistr)
|
||||
scenario2 = pc.DelegationFromProvisionPool(delegation, DelDistr)
|
||||
|
||||
// process the adjustment factors
|
||||
scenario1.UpdateAdjustmentForPowerChange(pc.Height)
|
||||
scenario2.UpdateAdjustmentForPowerChange(pc.Height)
|
||||
```
|
||||
|
||||
## TxWithdrawValidator
|
||||
|
||||
When a validator wishes to withdraw their transaction fees it must send
|
||||
`TxWithdrawDelegation`. Note that parts of this transaction logic is also
|
||||
triggered each with any change in individual delegations, such as an unbond,
|
||||
redelegation, or delegation of additional tokens to a specific validator. This
|
||||
transaction withdraws the validators commission rewards, as well as any rewards
|
||||
earning on their self-delegation.
|
||||
|
||||
```golang
|
||||
type TxWithdrawValidator struct {
|
||||
ownerAddr sdk.AccAddress // validator address to withdraw from
|
||||
withdrawAddr sdk.AccAddress // address to make the withdrawal to
|
||||
}
|
||||
|
||||
func WithdrawalValidator(ownerAddr, withdrawAddr sdk.AccAddress)
|
||||
|
||||
// update the delegator adjustment factors and also withdrawal delegation fees
|
||||
entitlement = GetDelegatorEntitlement(ownerAddr)
|
||||
|
||||
// update the validator adjustment factors for commission
|
||||
ValDistr = GetValidatorDistribution(ownerAddr.ValidatorAddr)
|
||||
pcs = GetPowerChanges(ValDistr.CommissionWithdrawalHeight)
|
||||
for pc = range pcs
|
||||
pc.ProcessPowerChangeCommission()
|
||||
|
||||
// withdrawal validator commission rewards
|
||||
global = GetGlobal()
|
||||
pool = GetPool()
|
||||
ValDistr = GetValidatorDistribution(delegation.ValidatorAddr)
|
||||
validator = GetValidator(delegation.ValidatorAddr)
|
||||
|
||||
scenerio1 = NewCommissionFromGlobalPool(validator,
|
||||
pool, global, ValDistr)
|
||||
scenerio2 = CommissionFromProposerPool(validator, ValDistr)
|
||||
entitlement += scenerio1.WithdrawalEntitlement()
|
||||
entitlement += scenerio2.WithdrawalEntitlement()
|
||||
|
||||
AddCoins(withdrawAddr, totalEntitlment.TruncateDecimal())
|
||||
|
||||
func (pc PowerChange) ProcessPowerChangeCommission()
|
||||
|
||||
// get the historical scenarios
|
||||
scenario1 = pc.CommissionFromGlobalPool()
|
||||
scenario2 = pc.CommissionFromProposerPool()
|
||||
|
||||
// process the adjustment factors
|
||||
scenario1.UpdateAdjustmentForPowerChange(pc.Height)
|
||||
scenario2.UpdateAdjustmentForPowerChange(pc.Height)
|
||||
```
|
||||
|
||||
## Common Calculations
|
||||
|
||||
### Distribution scenario
|
||||
|
||||
A common form of abstracted calculations exists between validators and
|
||||
delegations attempting to withdrawal their rewards, either from `Global.Pool`
|
||||
or from `ValidatorDistribution.ProposerPool`. With the following interface
|
||||
fulfilled the entitled fees for the various scenarios can be calculated.
|
||||
|
||||
```golang
|
||||
type DistributionScenario interface {
|
||||
DistributorTokens() DecCoins // current tokens from distributor
|
||||
DistributorCumulativeTokens() DecCoins // total tokens ever received
|
||||
DistributorPrevReceivedTokens() DecCoins // last value of tokens received
|
||||
DistributorShares() sdk.Dec // current shares
|
||||
DistributorPrevShares() sdk.Dec // shares last block
|
||||
|
||||
RecipientAdjustment() sdk.Dec
|
||||
RecipientShares() sdk.Dec // current shares
|
||||
RecipientPrevShares() sdk.Dec // shares last block
|
||||
|
||||
ModifyAdjustments(withdrawal sdk.Dec) // proceedure to modify adjustment factors
|
||||
}
|
||||
```
|
||||
|
||||
#### Entitled reward from distribution scenario
|
||||
|
||||
The entitlement to the distributor's tokens held can be accounted for lazily.
|
||||
To begin this calculation we must determine the recipient's _simple pool_ and
|
||||
_projected pool_. The simple pool represents a lazy accounting of what a
|
||||
recipient's entitlement to the distributor's tokens would be if all recipients
|
||||
for that distributor had static shares (equal to the current shares), and no
|
||||
recipients had ever withdrawn their entitled rewards. The projected pool
|
||||
represents the anticipated recipient's entitlement to the distributors tokens
|
||||
based on the current blocks token input (for example fees reward received) to
|
||||
the distributor, and the distributor's tokens and shares of the previous block
|
||||
assuming that neither had changed in the current block. Using the simple and
|
||||
projected pools we can determine all cumulative changes which have taken place
|
||||
outside of the recipient and adjust the recipient's _adjustment factor_ to
|
||||
account for these changes and ultimately keep track of the correct entitlement
|
||||
to the distributors tokens.
|
||||
|
||||
```
|
||||
func (d DistributionScenario) RecipientCount(height int64) sdk.Dec
|
||||
return v.RecipientShares() * height
|
||||
|
||||
func (d DistributionScenario) GlobalCount(height int64) sdk.Dec
|
||||
return d.DistributorShares() * height
|
||||
|
||||
func (d DistributionScenario) SimplePool() DecCoins
|
||||
return d.RecipientCount() / d.GlobalCount() * d.DistributorCumulativeTokens
|
||||
|
||||
func (d DistributionScenario) ProjectedPool(height int64) DecCoins
|
||||
return d.RecipientPrevShares() * (height-1)
|
||||
/ (d.DistributorPrevShares() * (height-1))
|
||||
* d.DistributorCumulativeTokens
|
||||
+ d.RecipientShares() / d.DistributorShares()
|
||||
* d.DistributorPrevReceivedTokens()
|
||||
```
|
||||
|
||||
The `DistributionScenario` _adjustment_ terms account for changes in
|
||||
recipient/distributor shares and recipient withdrawals. The adjustment factor
|
||||
must be modified whenever the recipient withdraws from the distributor or the
|
||||
distributor's/recipient's shares are changed.
|
||||
- When the shares of the recipient is changed the adjustment factor is
|
||||
increased/decreased by the difference between the _simple_ and _projected_
|
||||
pools. In other words, the cumulative difference in the shares if the shares
|
||||
has been the new shares as opposed to the old shares for the entire duration of
|
||||
the blockchain up the previous block.
|
||||
- When a recipient makes a withdrawal the adjustment factor is increased by the
|
||||
withdrawal amount.
|
||||
|
||||
```
|
||||
func (d DistributionScenario) UpdateAdjustmentForPowerChange(height int64)
|
||||
simplePool = d.SimplePool()
|
||||
projectedPool = d.ProjectedPool(height)
|
||||
AdjustmentChange = simplePool - projectedPool
|
||||
if AdjustmentChange > 0
|
||||
d.ModifyAdjustments(AdjustmentChange)
|
||||
|
||||
func (d DistributionScenario) WithdrawalEntitlement() DecCoins
|
||||
entitlement = d.SimplePool() - d.RecipientAdjustment()
|
||||
d.ModifyAdjustments(entitlement)
|
||||
return entitlement
|
||||
```
|
||||
|
||||
### Distribution scenarios
|
||||
|
||||
Note that the distribution scenario structures are found in `state.md`.
|
||||
|
||||
#### Delegation's entitlement to Global.Pool
|
||||
|
||||
For delegations (including validator's self-delegation) all fees from fee pool
|
||||
are subject to commission rate from the owner of the validator. The global
|
||||
shares should be taken as true number of global bonded shares. The recipients
|
||||
shares should be taken as the bonded tokens less the validator's commission.
|
||||
|
||||
```
|
||||
type DelegationFromGlobalPool struct {
|
||||
DelegationShares sdk.Dec
|
||||
ValidatorCommission sdk.Dec
|
||||
ValidatorBondedTokens sdk.Dec
|
||||
ValidatorDelegatorShareExRate sdk.Dec
|
||||
PoolBondedTokens sdk.Dec
|
||||
Global Global
|
||||
ValDistr ValidatorDistribution
|
||||
DelDistr DelegatorDistribution
|
||||
}
|
||||
|
||||
func (d DelegationFromGlobalPool) DistributorTokens() DecCoins
|
||||
return d.Global.Pool
|
||||
|
||||
func (d DelegationFromGlobalPool) DistributorCumulativeTokens() DecCoins
|
||||
return d.Global.EverReceivedPool
|
||||
|
||||
func (d DelegationFromGlobalPool) DistributorPrevReceivedTokens() DecCoins
|
||||
return d.Global.PrevReceivedPool
|
||||
|
||||
func (d DelegationFromGlobalPool) DistributorShares() sdk.Dec
|
||||
return d.PoolBondedTokens
|
||||
|
||||
func (d DelegationFromGlobalPool) DistributorPrevShares() sdk.Dec
|
||||
return d.Global.PrevBondedTokens
|
||||
|
||||
func (d DelegationFromGlobalPool) RecipientShares() sdk.Dec
|
||||
return d.DelegationShares * d.ValidatorDelegatorShareExRate() *
|
||||
d.ValidatorBondedTokens() * (1 - d.ValidatorCommission)
|
||||
|
||||
func (d DelegationFromGlobalPool) RecipientPrevShares() sdk.Dec
|
||||
return d.DelDistr.PrevTokens
|
||||
|
||||
func (d DelegationFromGlobalPool) RecipientAdjustment() sdk.Dec
|
||||
return d.DelDistr.Adjustment
|
||||
|
||||
func (d DelegationFromGlobalPool) ModifyAdjustments(withdrawal sdk.Dec)
|
||||
d.ValDistr.Adjustment += withdrawal
|
||||
d.DelDistr.Adjustment += withdrawal
|
||||
d.global.Adjustment += withdrawal
|
||||
SetValidatorDistribution(d.ValDistr)
|
||||
SetDelegatorDistribution(d.DelDistr)
|
||||
SetGlobal(d.Global)
|
||||
```
|
||||
|
||||
#### Delegation's entitlement to ValidatorDistribution.ProposerPool
|
||||
|
||||
Delegations (including validator's self-delegation) are still subject
|
||||
commission on the rewards gained from the proposer pool. Global shares in this
|
||||
context is actually the validators total delegations shares. The recipient's
|
||||
shares is taken as the effective delegation shares less the validator's
|
||||
commission.
|
||||
|
||||
```
|
||||
type DelegationFromProposerPool struct {
|
||||
DelegationShares sdk.Dec
|
||||
ValidatorCommission sdk.Dec
|
||||
ValidatorDelegatorShares sdk.Dec
|
||||
ValDistr ValidatorDistribution
|
||||
DelDistr DelegatorDistribution
|
||||
}
|
||||
|
||||
func (d DelegationFromProposerPool) DistributorTokens() DecCoins
|
||||
return d.ValDistr.ProposerPool
|
||||
|
||||
func (d DelegationFromProposerPool) DistributorCumulativeTokens() DecCoins
|
||||
return d.ValDistr.EverReceivedProposerReward
|
||||
|
||||
func (d DelegationFromProposerPool) DistributorPrevReceivedTokens() DecCoins
|
||||
return d.ValDistr.PrevReceivedProposerReward
|
||||
|
||||
func (d DelegationFromProposerPool) DistributorShares() sdk.Dec
|
||||
return d.ValidatorDelegatorShares
|
||||
|
||||
func (d DelegationFromProposerPool) DistributorPrevShares() sdk.Dec
|
||||
return d.ValDistr.PrevDelegatorShares
|
||||
|
||||
func (d DelegationFromProposerPool) RecipientShares() sdk.Dec
|
||||
return d.DelegationShares * (1 - d.ValidatorCommission)
|
||||
|
||||
func (d DelegationFromProposerPool) RecipientPrevShares() sdk.Dec
|
||||
return d.DelDistr.PrevShares
|
||||
|
||||
func (d DelegationFromProposerPool) RecipientAdjustment() sdk.Dec
|
||||
return d.DelDistr.AdjustmentProposer
|
||||
|
||||
func (d DelegationFromProposerPool) ModifyAdjustments(withdrawal sdk.Dec)
|
||||
d.ValDistr.AdjustmentProposer += withdrawal
|
||||
d.DelDistr.AdjustmentProposer += withdrawal
|
||||
SetValidatorDistribution(d.ValDistr)
|
||||
SetDelegatorDistribution(d.DelDistr)
|
||||
```
|
||||
|
||||
#### Validators's commission entitlement to Global.Pool
|
||||
|
||||
Similar to a delegator's entitlement, but with recipient shares based on the
|
||||
commission portion of bonded tokens.
|
||||
|
||||
```
|
||||
type CommissionFromGlobalPool struct {
|
||||
ValidatorBondedTokens sdk.Dec
|
||||
ValidatorCommission sdk.Dec
|
||||
PoolBondedTokens sdk.Dec
|
||||
Global Global
|
||||
ValDistr ValidatorDistribution
|
||||
}
|
||||
|
||||
func (c CommissionFromGlobalPool) DistributorTokens() DecCoins
|
||||
return c.Global.Pool
|
||||
|
||||
func (c CommissionFromGlobalPool) DistributorCumulativeTokens() DecCoins
|
||||
return c.Global.EverReceivedPool
|
||||
|
||||
func (c CommissionFromGlobalPool) DistributorPrevReceivedTokens() DecCoins
|
||||
return c.Global.PrevReceivedPool
|
||||
|
||||
func (c CommissionFromGlobalPool) DistributorShares() sdk.Dec
|
||||
return c.PoolBondedTokens
|
||||
|
||||
func (c CommissionFromGlobalPool) DistributorPrevShares() sdk.Dec
|
||||
return c.Global.PrevBondedTokens
|
||||
|
||||
func (c CommissionFromGlobalPool) RecipientShares() sdk.Dec
|
||||
return c.ValidatorBondedTokens() * c.ValidatorCommission
|
||||
|
||||
func (c CommissionFromGlobalPool) RecipientPrevShares() sdk.Dec
|
||||
return c.ValDistr.PrevBondedTokens * c.ValidatorCommission
|
||||
|
||||
func (c CommissionFromGlobalPool) RecipientAdjustment() sdk.Dec
|
||||
return c.ValDistr.Adjustment
|
||||
|
||||
func (c CommissionFromGlobalPool) ModifyAdjustments(withdrawal sdk.Dec)
|
||||
c.ValDistr.Adjustment += withdrawal
|
||||
c.Global.Adjustment += withdrawal
|
||||
SetValidatorDistribution(c.ValDistr)
|
||||
SetGlobal(c.Global)
|
||||
```
|
||||
|
||||
#### Validators's commission entitlement to ValidatorDistribution.ProposerPool
|
||||
|
||||
Similar to a delegators entitlement to the proposer pool, but with recipient
|
||||
shares based on the commission portion of the total delegator shares.
|
||||
|
||||
```
|
||||
type CommissionFromProposerPool struct {
|
||||
ValidatorDelegatorShares sdk.Dec
|
||||
ValidatorCommission sdk.Dec
|
||||
ValDistr ValidatorDistribution
|
||||
}
|
||||
|
||||
func (c CommissionFromProposerPool) DistributorTokens() DecCoins
|
||||
return c.ValDistr.ProposerPool
|
||||
|
||||
func (c CommissionFromProposerPool) DistributorCumulativeTokens() DecCoins
|
||||
return c.ValDistr.EverReceivedProposerReward
|
||||
|
||||
func (c CommissionFromProposerPool) DistributorPrevReceivedTokens() DecCoins
|
||||
return c.ValDistr.PrevReceivedProposerReward
|
||||
|
||||
func (c CommissionFromProposerPool) DistributorShares() sdk.Dec
|
||||
return c.ValidatorDelegatorShares
|
||||
|
||||
func (c CommissionFromProposerPool) DistributorPrevShares() sdk.Dec
|
||||
return c.ValDistr.PrevDelegatorShares
|
||||
|
||||
func (c CommissionFromProposerPool) RecipientShares() sdk.Dec
|
||||
return c.ValidatorDelegatorShares * (c.ValidatorCommission)
|
||||
|
||||
func (c CommissionFromProposerPool) RecipientPrevShares() sdk.Dec
|
||||
return c.ValDistr.PrevDelegatorShares * (c.ValidatorCommission)
|
||||
|
||||
func (c CommissionFromProposerPool) RecipientAdjustment() sdk.Dec
|
||||
return c.ValDistr.AdjustmentProposer
|
||||
|
||||
func (c CommissionFromProposerPool) ModifyAdjustments(withdrawal sdk.Dec)
|
||||
c.ValDistr.AdjustmentProposer += withdrawal
|
||||
SetValidatorDistribution(c.ValDistr)
|
||||
```
|
||||
|
|
@ -139,6 +139,17 @@ gaiacli send \
|
|||
--dry-run
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
#### Set up a Validator
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
# End Block
|
||||
|
||||
At each endblock, the fees received are sorted to the proposer, community fund,
|
||||
At each endblock, the fees received are allocated to the proposer, community fund,
|
||||
and global pool. When the validator is the proposer of the round, that
|
||||
validator (and their delegators) receives between 1% and 5% of fee rewards, the
|
||||
reserve tax is then charged, then the remainder is distributed proportionally
|
||||
by voting power to all bonded validators independent of whether they voted
|
||||
(social distribution). Note the social distribution is applied to proposer
|
||||
validator in addition to the proposer reward.
|
||||
reserve community tax is then charged, then the remainder is distributed
|
||||
proportionally by voting power to all bonded validators independent of whether
|
||||
they voted (social distribution). Note the social distribution is applied to
|
||||
proposer validator in addition to the proposer reward.
|
||||
|
||||
The amount of proposer reward is calculated from pre-commits Tendermint
|
||||
messages in order to incentivize validators to wait and include additional
|
||||
|
@ -15,13 +15,17 @@ pool which validator holds individually
|
|||
(`ValidatorDistribution.ProvisionsRewardPool`).
|
||||
|
||||
```
|
||||
func SortFees(feesCollected sdk.Coins, global Global, proposer ValidatorDistribution,
|
||||
sumPowerPrecommitValidators, totalBondedTokens, communityTax sdk.Dec)
|
||||
func AllocateFees(feesCollected sdk.Coins, global Global, proposer ValidatorDistribution,
|
||||
sumPowerPrecommitValidators, totalBondedTokens, communityTax,
|
||||
proposerCommissionRate sdk.Dec)
|
||||
|
||||
feesCollectedDec = MakeDecCoins(feesCollected)
|
||||
proposerReward = feesCollectedDec * (0.01 + 0.04
|
||||
* sumPowerPrecommitValidators / totalBondedTokens)
|
||||
proposer.ProposerPool += proposerReward
|
||||
|
||||
commission = proposerReward * proposerCommissionRate
|
||||
proposer.PoolCommission += commission
|
||||
proposer.Pool += proposerReward - commission
|
||||
|
||||
communityFunding = feesCollectedDec * communityTax
|
||||
global.CommunityFund += communityFunding
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
# Hooks
|
||||
|
||||
## Create or modify delegation distribution
|
||||
|
||||
- triggered-by: `stake.TxDelegate`, `stake.TxBeginRedelegate`, `stake.TxBeginUnbonding`
|
||||
|
||||
The pool of a new delegator bond will be 0 for the height at which the bond was
|
||||
added, or the withdrawal has taken place. This is achieved by setting
|
||||
`DelegatorDistInfo.WithdrawalHeight` to the height of the triggering transaction.
|
||||
|
||||
## Commission rate change
|
||||
|
||||
- triggered-by: `stake.TxEditValidator`
|
||||
|
||||
If a validator changes its commission rate, all commission on fees must be
|
||||
simultaneously withdrawn using the transaction `TxWithdrawValidator`.
|
||||
Additionally the change and associated height must be recorded in a
|
||||
`ValidatorUpdate` state record.
|
||||
|
||||
## Change in Validator State
|
||||
|
||||
- triggered-by: `stake.Slash`, `stake.UpdateValidator`
|
||||
|
||||
Whenever a validator is slashed or enters/leaves the validator group all of the
|
||||
validator entitled reward tokens must be simultaneously withdrawn from
|
||||
`Global.Pool` and added to `ValidatorDistInfo.Pool`.
|
|
@ -2,53 +2,71 @@
|
|||
|
||||
## Overview
|
||||
|
||||
Collected fees are pooled globally and divided out passively to validators and
|
||||
delegators. Each validator has the opportunity to charge commission to the
|
||||
delegators on the fees collected on behalf of the delegators by the validators.
|
||||
Fees are paid directly into a global fee pool, and validator proposer-reward
|
||||
pool. Due to the nature of passive accounting whenever changes to parameters
|
||||
which affect the rate of fee distribution occurs, withdrawal of fees must also
|
||||
occur when:
|
||||
This _simple_ distribution mechanism describes a functional way to passively
|
||||
distribute rewards between validator and delegators. Note that this mechanism does
|
||||
not distribute funds in as precisely as active reward distribution and will therefore
|
||||
be upgraded in the future.
|
||||
|
||||
- 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 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.
|
||||
|
||||
The above scenarios are covered in `triggers.md`.
|
||||
- Whenever withdrawing, one must withdraw the maximum amount they are entitled
|
||||
too, leaving nothing in the pool.
|
||||
- Whenever bonding, unbonding, or re-delegating tokens to an existing account, a
|
||||
full withdrawal of the rewards must occur (as the rules for lazy accounting
|
||||
change).
|
||||
- Whenever a validator chooses to change the commission on rewards, all accumulated
|
||||
commission rewards must be simultaneously withdrawn.
|
||||
|
||||
The above scenarios are covered in `hooks.md`.
|
||||
|
||||
The distribution mechanism outlines herein is used to lazily distribute the
|
||||
following between validators and associated delegators:
|
||||
following rewards between validators and associated delegators:
|
||||
- multi-token fees to be socially distributed,
|
||||
- proposer reward pool,
|
||||
- inflated atom provisions, and
|
||||
- validator commission on all rewards earned by their delegators stake
|
||||
|
||||
Fees are pooled within a global pool, as well as validator specific
|
||||
proposer-reward pools. The mechanisms used allow for validators and delegators
|
||||
to independently and lazily withdrawn their rewards. As a part of the lazy
|
||||
computations adjustment factors must be maintained for each validator and
|
||||
delegator to determine the true proportion of fees in each pool which they are
|
||||
entitled too. Adjustment factors are updated every time a validator or
|
||||
delegator's voting power changes. Validators and delegators must withdraw all
|
||||
fees they are entitled too before they can change their portion of bonded
|
||||
Atoms.
|
||||
proposer-reward pools. The mechanisms used allow for validators and delegators
|
||||
to independently and lazily withdraw their rewards.
|
||||
|
||||
## Shortcomings
|
||||
|
||||
As a part of the lazy computations, each delegator holds an accumulation term
|
||||
specific to each validator which is used to estimate what their approximate
|
||||
fair portion of tokens held in the global pool is owed to them.
|
||||
|
||||
```
|
||||
entitlement = delegator-accumulation / all-delegators-accumulation
|
||||
```
|
||||
|
||||
Under the circumstance that there were constant and equal flow of incoming
|
||||
reward tokens every block, this distribution mechanism would be equal to the
|
||||
active distribution (distribute individually to all delegators each block).
|
||||
However this is unrealistic so deviations from the active distribution will
|
||||
occur based on fluctuations of incoming reward tokens as well as timing of
|
||||
reward withdrawal by other delegators.
|
||||
|
||||
If you happen to know that incoming rewards are about significantly move up,
|
||||
you are incentivized to not withdraw until after this event, increasing the
|
||||
worth of your existing _accum_.
|
||||
|
||||
## Affect on Staking
|
||||
|
||||
|
||||
Charging commission on Atom provisions while also allowing for Atom-provisions
|
||||
to be auto-bonded (distributed directly to the validators bonded stake) is
|
||||
problematic within DPoS. Fundamentally these two mechnisms are mutually
|
||||
exclusive. If there are atoms commissions and auto-bonding Atoms, the portion
|
||||
of Atoms the fee distribution calculation would become very large as the Atom
|
||||
portion for each delegator would change each block making a withdrawal of fees
|
||||
problematic within DPoS. Fundamentally these two mechanisms are mutually
|
||||
exclusive. If there are Atom commissions and auto-bonding Atoms, the portion
|
||||
of Atoms the reward distribution calculation would become very large as the Atom
|
||||
portion for each delegator would change each block making a withdrawal of rewards
|
||||
for a delegator require a calculation for every single block since the last
|
||||
withdrawal. In conclusion we can only have atom commission and unbonded atoms
|
||||
provisions, or bonded atom provisions with no Atom commission, and we elect to
|
||||
withdrawal. In conclusion, we can only have Atom commission and unbonded atoms
|
||||
provisions or bonded atom provisions with no Atom commission, and we elect to
|
||||
implement the former. Stakeholders wishing to rebond their provisions may elect
|
||||
to set up a script to periodically withdraw and rebond fees.
|
||||
|
||||
to set up a script to periodically withdraw and rebond rewards.
|
||||
|
|
|
@ -23,78 +23,46 @@ type DecCoin struct {
|
|||
}
|
||||
|
||||
type Global struct {
|
||||
PrevBondedTokens sdk.Dec // bonded token amount for the global pool on the previous block
|
||||
Adjustment sdk.Dec // global adjustment factor for lazy calculations
|
||||
Pool DecCoins // funds for all validators which have yet to be withdrawn
|
||||
PrevReceivedPool DecCoins // funds added to the pool on the previous block
|
||||
EverReceivedPool DecCoins // total funds ever added to the pool
|
||||
CommunityFund DecCoins // pool for community funds yet to be spent
|
||||
TotalValAccumUpdateHeight int64 // last height which the total validator accum was updated
|
||||
TotalValAccum sdk.Dec // total valdator accum held by validators
|
||||
Pool DecCoins // funds for all validators which have yet to be withdrawn
|
||||
CommunityPool DecCoins // pool for community funds yet to be spent
|
||||
}
|
||||
```
|
||||
|
||||
### Validator Distribution
|
||||
|
||||
Validator distribution information for the relevant validator is updated each time:
|
||||
1. delegation amount to a validator are updated,
|
||||
1. delegation amount to a validator is updated,
|
||||
2. a validator successfully proposes a block and receives a reward,
|
||||
3. any delegator withdraws from a validator, or
|
||||
4. the validator withdraws it's commission.
|
||||
|
||||
- ValidatorDistribution: `0x02 | ValOwnerAddr -> amino(validatorDistribution)`
|
||||
- ValidatorDistInfo: `0x02 | ValOperatorAddr -> amino(validatorDistribution)`
|
||||
|
||||
```golang
|
||||
type ValidatorDistribution struct {
|
||||
CommissionWithdrawalHeight int64 // last time this validator withdrew commission
|
||||
Adjustment sdk.Dec // global pool adjustment factor
|
||||
ProposerAdjustment DecCoins // proposer pool adjustment factor
|
||||
ProposerPool DecCoins // reward pool collected from being the proposer
|
||||
EverReceivedProposerReward DecCoins // all rewards ever collected from being the proposer
|
||||
PrevReceivedProposerReward DecCoins // previous rewards collected from being the proposer
|
||||
PrevBondedTokens sdk.Dec // bonded token amount on the previous block
|
||||
PrevDelegatorShares sdk.Dec // amount of delegator shares for the validator on the previous block
|
||||
type ValidatorDistInfo struct {
|
||||
GlobalWithdrawalHeight int64 // last height this validator withdrew from the global pool
|
||||
Pool DecCoins // rewards owed to delegators, commission has already been charged (includes proposer reward)
|
||||
PoolCommission DecCoins // commission collected by this validator (pending withdrawal)
|
||||
|
||||
TotalDelAccumUpdateHeight int64 // last height which the total delegator accum was updated
|
||||
TotalDelAccum sdk.Dec // total proposer pool accumulation factor held by delegators
|
||||
}
|
||||
```
|
||||
|
||||
### Delegation Distribution
|
||||
|
||||
Each delegation holds multiple adjustment factors to specify its entitlement to
|
||||
the rewards from a validator. `AdjustmentPool` is used to passively calculate
|
||||
each bonds entitled fees from the `RewardPool`. `AdjustmentPool` is used to
|
||||
passively calculate each bonds entitled fees from
|
||||
`ValidatorDistribution.ProposerRewardPool`
|
||||
Each delegation distribution only needs to record the height at which it last
|
||||
withdrew fees. Because a delegation must withdraw fees each time it's
|
||||
properties change (aka bonded tokens etc.) its properties will remain constant
|
||||
and the delegator's _accumulation_ factor can be calculated passively knowing
|
||||
only the height of the last withdrawal and its current properties.
|
||||
|
||||
- DelegatorDistribution: ` 0x02 | DelegatorAddr | ValOwnerAddr -> amino(delegatorDist)`
|
||||
- DelegatorDistInfo: ` 0x02 | DelegatorAddr | ValOperatorAddr -> amino(delegatorDist)`
|
||||
|
||||
```golang
|
||||
type DelegatorDist struct {
|
||||
WithdrawalHeight int64 // last time this delegation withdrew rewards
|
||||
Adjustment sdk.Dec // fee provisioning adjustment factor
|
||||
AdjustmentProposer DecCoins // proposers pool adjustment factor
|
||||
PrevTokens sdk.Dec // bonded tokens held by the delegation on the previous block
|
||||
PrevShares sdk.Dec // delegator shares held by the delegation on the previous block
|
||||
}
|
||||
```
|
||||
|
||||
### Power Change
|
||||
|
||||
Every instance that the voting power changes, information about the state of
|
||||
the validator set during the change must be recorded as a `PowerChange` for
|
||||
other validators to run through. Each power change is indexed by its block
|
||||
height.
|
||||
|
||||
- PowerChange: `0x03 | amino(Height) -> amino(validatorDist)`
|
||||
|
||||
```golang
|
||||
type PowerChange struct {
|
||||
Height int64 // block height at change
|
||||
ValidatorBondedTokens sdk.Dec // following used to create distribution scenarios
|
||||
ValidatorDelegatorShares sdk.Dec
|
||||
ValidatorDelegatorShareExRate sdk.Dec
|
||||
ValidatorCommission sdk.Dec
|
||||
PoolBondedTokens sdk.Dec
|
||||
Global Global
|
||||
ValDistr ValidatorDistribution
|
||||
DelegationShares sdk.Dec
|
||||
DelDistr DelegatorDistribution
|
||||
type DelegatorDistInfo struct {
|
||||
WithdrawalHeight int64 // last time this delegation withdrew rewards
|
||||
}
|
||||
```
|
||||
|
|
|
@ -1,399 +1,213 @@
|
|||
# Transactions
|
||||
|
||||
## TxWithdrawDelegation
|
||||
## TxWithdrawDelegationRewardsAll
|
||||
|
||||
When a delegator wishes to withdraw their transaction fees it must send
|
||||
`TxWithdrawDelegation`. Note that parts of this transaction logic are also
|
||||
When a delegator wishes to withdraw their rewards it must send
|
||||
`TxWithdrawDelegationRewardsAll`. Note that parts of this transaction logic are also
|
||||
triggered each with any change in individual delegations, such as an unbond,
|
||||
redelegation, or delegation of additional tokens to a specific validator.
|
||||
|
||||
Each time a withdrawal is made by a recipient the adjustment term must be
|
||||
modified for each block with a change in distributors shares since the time of
|
||||
last withdrawal. This is accomplished by iterating over all relevant
|
||||
`PowerChange`'s stored in distribution state.
|
||||
|
||||
|
||||
```golang
|
||||
type TxWithdrawDelegation struct {
|
||||
type TxWithdrawDelegationRewardsAll struct {
|
||||
delegatorAddr sdk.AccAddress
|
||||
withdrawAddr sdk.AccAddress // address to make the withdrawal to
|
||||
}
|
||||
|
||||
func WithdrawDelegator(delegatorAddr, withdrawAddr sdk.AccAddress)
|
||||
entitlement = GetDelegatorEntitlement(delegatorAddr)
|
||||
AddCoins(withdrawAddr, totalEntitlment.TruncateDecimal())
|
||||
func WithdrawDelegationRewardsAll(delegatorAddr, withdrawAddr sdk.AccAddress)
|
||||
height = GetHeight()
|
||||
withdraw = GetDelegatorRewardsAll(delegatorAddr, height)
|
||||
AddCoins(withdrawAddr, withdraw.TruncateDecimal())
|
||||
|
||||
func GetDelegatorEntitlement(delegatorAddr sdk.AccAddress) DecCoins
|
||||
func GetDelegatorRewardsAll(delegatorAddr sdk.AccAddress, height int64) DecCoins
|
||||
|
||||
// compile all the distribution scenarios
|
||||
// get all distribution scenarios
|
||||
delegations = GetDelegations(delegatorAddr)
|
||||
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
|
||||
delegation.ValidatorAddr)
|
||||
pcs = GetPowerChanges(DelDistr.WithdrawalHeight)
|
||||
|
||||
// update all adjustment factors for each delegation since last withdrawal
|
||||
for pc = range pcs
|
||||
for delegation = range delegations
|
||||
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
|
||||
delegation.ValidatorAddr)
|
||||
pc.ProcessPowerChangeDelegation(delegation, DelDistr)
|
||||
|
||||
// collect all entitled fees
|
||||
entitlement = 0
|
||||
// collect all entitled rewards
|
||||
withdraw = 0
|
||||
pool = stake.GetPool()
|
||||
global = GetGlobal()
|
||||
for delegation = range delegations
|
||||
global = GetGlobal()
|
||||
pool = GetPool()
|
||||
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
|
||||
delInfo = GetDelegationDistInfo(delegation.DelegatorAddr,
|
||||
delegation.ValidatorAddr)
|
||||
ValDistr = GetValidatorDistribution(delegation.ValidatorAddr)
|
||||
valInfo = GetValidatorDistInfo(delegation.ValidatorAddr)
|
||||
validator = GetValidator(delegation.ValidatorAddr)
|
||||
|
||||
scenerio1 = NewDelegationFromGlobalPool(delegation, validator,
|
||||
pool, global, ValDistr, DelDistr)
|
||||
scenerio2 = NewDelegationFromProvisionPool(delegation, validator,
|
||||
ValDistr, DelDistr)
|
||||
entitlement += scenerio1.WithdrawalEntitlement()
|
||||
entitlement += scenerio2.WithdrawalEntitlement()
|
||||
global, diWithdraw = delInfo.WithdrawRewards(global, valInfo, height, pool.BondedTokens,
|
||||
validator.Tokens, validator.DelegatorShares, validator.Commission)
|
||||
withdraw += diWithdraw
|
||||
|
||||
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)
|
||||
SetGlobal(global)
|
||||
return withdraw
|
||||
```
|
||||
|
||||
## TxWithdrawValidator
|
||||
## TxWithdrawDelegationReward
|
||||
|
||||
When a validator wishes to withdraw their transaction fees it must send
|
||||
`TxWithdrawDelegation`. Note that parts of this transaction logic is also
|
||||
triggered each with any change in individual delegations, such as an unbond,
|
||||
redelegation, or delegation of additional tokens to a specific validator. This
|
||||
transaction withdraws the validators commission rewards, as well as any rewards
|
||||
earning on their self-delegation.
|
||||
under special circumstances a delegator may wish to withdraw rewards from only
|
||||
a single validator.
|
||||
|
||||
```golang
|
||||
type TxWithdrawValidator struct {
|
||||
ownerAddr sdk.AccAddress // validator address to withdraw from
|
||||
type TxWithdrawDelegationReward struct {
|
||||
delegatorAddr sdk.AccAddress
|
||||
validatorAddr sdk.AccAddress
|
||||
withdrawAddr sdk.AccAddress // address to make the withdrawal to
|
||||
}
|
||||
|
||||
func WithdrawDelegationReward(delegatorAddr, validatorAddr, withdrawAddr sdk.AccAddress)
|
||||
height = GetHeight()
|
||||
|
||||
// get all distribution scenarios
|
||||
pool = stake.GetPool()
|
||||
global = GetGlobal()
|
||||
delInfo = GetDelegationDistInfo(delegatorAddr,
|
||||
validatorAddr)
|
||||
valInfo = GetValidatorDistInfo(validatorAddr)
|
||||
validator = GetValidator(validatorAddr)
|
||||
|
||||
global, withdraw = delInfo.WithdrawRewards(global, valInfo, height, pool.BondedTokens,
|
||||
validator.Tokens, validator.DelegatorShares, validator.Commission)
|
||||
|
||||
SetGlobal(global)
|
||||
AddCoins(withdrawAddr, withdraw.TruncateDecimal())
|
||||
```
|
||||
|
||||
|
||||
## TxWithdrawValidatorRewardsAll
|
||||
|
||||
When a validator wishes to withdraw their rewards it must send
|
||||
`TxWithdrawValidatorRewardsAll`. Note that parts of this transaction logic are also
|
||||
triggered each with any change in individual delegations, such as an unbond,
|
||||
redelegation, or delegation of additional tokens to a specific validator. This
|
||||
transaction withdraws the validators commission fee, as well as any rewards
|
||||
earning on their self-delegation.
|
||||
|
||||
```
|
||||
type TxWithdrawValidatorRewardsAll struct {
|
||||
operatorAddr sdk.AccAddress // validator address to withdraw from
|
||||
withdrawAddr sdk.AccAddress // address to make the withdrawal to
|
||||
}
|
||||
|
||||
func WithdrawalValidator(ownerAddr, withdrawAddr sdk.AccAddress)
|
||||
func WithdrawValidatorRewardsAll(operatorAddr, withdrawAddr sdk.AccAddress)
|
||||
|
||||
// update the delegator adjustment factors and also withdrawal delegation fees
|
||||
entitlement = GetDelegatorEntitlement(ownerAddr)
|
||||
|
||||
// update the validator adjustment factors for commission
|
||||
ValDistr = GetValidatorDistribution(ownerAddr.ValidatorAddr)
|
||||
pcs = GetPowerChanges(ValDistr.CommissionWithdrawalHeight)
|
||||
for pc = range pcs
|
||||
pc.ProcessPowerChangeCommission()
|
||||
|
||||
// withdrawal validator commission rewards
|
||||
height = GetHeight()
|
||||
global = GetGlobal()
|
||||
pool = GetPool()
|
||||
ValDistr = GetValidatorDistribution(delegation.ValidatorAddr)
|
||||
ValInfo = GetValidatorDistInfo(delegation.ValidatorAddr)
|
||||
validator = GetValidator(delegation.ValidatorAddr)
|
||||
|
||||
scenerio1 = NewCommissionFromGlobalPool(validator,
|
||||
pool, global, ValDistr)
|
||||
scenerio2 = CommissionFromProposerPool(validator, ValDistr)
|
||||
entitlement += scenerio1.WithdrawalEntitlement()
|
||||
entitlement += scenerio2.WithdrawalEntitlement()
|
||||
// withdraw self-delegation
|
||||
withdraw = GetDelegatorRewardsAll(validator.OperatorAddr, height)
|
||||
|
||||
AddCoins(withdrawAddr, totalEntitlment.TruncateDecimal())
|
||||
// withdrawal validator commission rewards
|
||||
global, commission = valInfo.WithdrawCommission(global, valInfo, height, pool.BondedTokens,
|
||||
validator.Tokens, validator.Commission)
|
||||
withdraw += commission
|
||||
SetGlobal(global)
|
||||
|
||||
func (pc PowerChange) ProcessPowerChangeCommission()
|
||||
|
||||
// get the historical scenarios
|
||||
scenario1 = pc.CommissionFromGlobalPool()
|
||||
scenario2 = pc.CommissionFromProposerPool()
|
||||
|
||||
// process the adjustment factors
|
||||
scenario1.UpdateAdjustmentForPowerChange(pc.Height)
|
||||
scenario2.UpdateAdjustmentForPowerChange(pc.Height)
|
||||
AddCoins(withdrawAddr, withdraw.TruncateDecimal())
|
||||
```
|
||||
|
||||
## Common Calculations
|
||||
## Common calculations
|
||||
|
||||
### Distribution scenario
|
||||
### Update total validator accum
|
||||
|
||||
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.
|
||||
The total amount of validator accum must be calculated in order to determine
|
||||
the amount of pool tokens which a validator is entitled to at a particular
|
||||
block. The accum is always additive to the existing accum. This term is to be
|
||||
updated each time rewards are withdrawn from the system.
|
||||
|
||||
```
|
||||
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()
|
||||
func (g Global) UpdateTotalValAccum(height int64, totalBondedTokens Dec) Global
|
||||
blocks = height - g.TotalValAccumUpdateHeight
|
||||
g.TotalValAccum += totalDelShares * blocks
|
||||
g.TotalValAccumUpdateHeight = height
|
||||
return g
|
||||
```
|
||||
|
||||
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.
|
||||
### Update validator's accums
|
||||
|
||||
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.
|
||||
|
||||
```
|
||||
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
|
||||
func (vi ValidatorDistInfo) UpdateTotalDelAccum(height int64, totalDelShares Dec) ValidatorDistInfo
|
||||
blocks = height - vi.TotalDelAccumUpdateHeight
|
||||
vi.TotalDelAccum += totalDelShares * blocks
|
||||
vi.TotalDelAccumUpdateHeight = height
|
||||
return vi
|
||||
```
|
||||
|
||||
### Distribution scenarios
|
||||
### Global pool to validator pool
|
||||
|
||||
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.
|
||||
Every time a validator or delegator executes a withdrawal or the validator is
|
||||
the proposer and receives new tokens, the relevant validator must move tokens
|
||||
from the passive global pool to their own pool. It is at this point that the
|
||||
commission is withdrawn
|
||||
|
||||
```
|
||||
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 (vi ValidatorDistInfo) TakeAccum(g Global, height int64, totalBonded, vdTokens, commissionRate Dec) (
|
||||
vi ValidatorDistInfo, g Global)
|
||||
|
||||
func (d DelegationFromGlobalPool) DistributorTokens() DecCoins
|
||||
return d.Global.Pool
|
||||
g.UpdateTotalValAccum(height, totalBondedShares)
|
||||
|
||||
func (d DelegationFromGlobalPool) DistributorCumulativeTokens() DecCoins
|
||||
return d.Global.EverReceivedPool
|
||||
// update the validators pool
|
||||
blocks = height - vi.GlobalWithdrawalHeight
|
||||
vi.GlobalWithdrawalHeight = height
|
||||
accum = blocks * vdTokens
|
||||
withdrawalTokens := g.Pool * accum / g.TotalValAccum
|
||||
commission := withdrawalTokens * commissionRate
|
||||
|
||||
func (d DelegationFromGlobalPool) DistributorPrevReceivedTokens() DecCoins
|
||||
return d.Global.PrevReceivedPool
|
||||
g.TotalValAccum -= accumm
|
||||
vi.PoolCommission += commission
|
||||
vi.PoolCommissionFree += withdrawalTokens - commission
|
||||
g.Pool -= withdrawalTokens
|
||||
|
||||
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)
|
||||
return vi, g
|
||||
```
|
||||
|
||||
#### 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.
|
||||
### Delegation reward withdrawal
|
||||
|
||||
For delegations (including validator's self-delegation) all rewards from reward
|
||||
pool have already had the validator's commission taken away.
|
||||
|
||||
```
|
||||
type DelegationFromProposerPool struct {
|
||||
DelegationShares sdk.Dec
|
||||
ValidatorCommission sdk.Dec
|
||||
ValidatorDelegatorShares sdk.Dec
|
||||
ValDistr ValidatorDistribution
|
||||
DelDistr DelegatorDistribution
|
||||
}
|
||||
func (di DelegatorDistInfo) WithdrawRewards(g Global, vi ValidatorDistInfo,
|
||||
height int64, totalBonded, vdTokens, totalDelShares, commissionRate Dec) (
|
||||
di DelegatorDistInfo, g Global, withdrawn DecCoins)
|
||||
|
||||
func (d DelegationFromProposerPool) DistributorTokens() DecCoins
|
||||
return d.ValDistr.ProposerPool
|
||||
vi.UpdateTotalDelAccum(height, totalDelShares)
|
||||
g = vi.TakeAccum(g, height, totalBonded, vdTokens, commissionRate)
|
||||
|
||||
func (d DelegationFromProposerPool) DistributorCumulativeTokens() DecCoins
|
||||
return d.ValDistr.EverReceivedProposerReward
|
||||
blocks = height - di.WithdrawalHeight
|
||||
di.WithdrawalHeight = height
|
||||
accum = delegatorShares * blocks
|
||||
|
||||
func (d DelegationFromProposerPool) DistributorPrevReceivedTokens() DecCoins
|
||||
return d.ValDistr.PrevReceivedProposerReward
|
||||
withdrawalTokens := vi.Pool * accum / vi.TotalDelAccum
|
||||
vi.TotalDelAccum -= accum
|
||||
|
||||
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.
|
||||
vi.Pool -= withdrawalTokens
|
||||
vi.TotalDelAccum -= accum
|
||||
return di, g, withdrawalTokens
|
||||
|
||||
```
|
||||
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
|
||||
### Validator commission withdrawal
|
||||
|
||||
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.
|
||||
Commission is calculated each time rewards enter into the validator.
|
||||
|
||||
```
|
||||
type CommissionFromProposerPool struct {
|
||||
ValidatorDelegatorShares sdk.Dec
|
||||
ValidatorCommission sdk.Dec
|
||||
ValDistr ValidatorDistribution
|
||||
}
|
||||
func (vi ValidatorDistInfo) WithdrawCommission(g Global, height int64,
|
||||
totalBonded, vdTokens, commissionRate Dec) (
|
||||
vi ValidatorDistInfo, g Global, withdrawn DecCoins)
|
||||
|
||||
func (c CommissionFromProposerPool) DistributorTokens() DecCoins
|
||||
return c.ValDistr.ProposerPool
|
||||
g = vi.TakeAccum(g, height, totalBonded, vdTokens, commissionRate)
|
||||
|
||||
func (c CommissionFromProposerPool) DistributorCumulativeTokens() DecCoins
|
||||
return c.ValDistr.EverReceivedProposerReward
|
||||
withdrawalTokens := vi.PoolCommission
|
||||
vi.PoolCommission = 0
|
||||
|
||||
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)
|
||||
return vi, g, withdrawalTokens
|
||||
```
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ func GetAssocKey(base sdk.ValAddress, assoc sdk.ValAddress) []byte {
|
|||
}
|
||||
|
||||
// Associate associates new address with validator address
|
||||
// nolint: unparam
|
||||
func (valset ValidatorSet) Associate(ctx sdk.Context, base sdk.ValAddress, assoc sdk.ValAddress) bool {
|
||||
if len(base) != valset.addrLen || len(assoc) != valset.addrLen {
|
||||
return false
|
||||
|
@ -76,6 +77,7 @@ func (valset ValidatorSet) Associate(ctx sdk.Context, base sdk.ValAddress, assoc
|
|||
}
|
||||
|
||||
// Dissociate removes association between addresses
|
||||
// nolint: unparam
|
||||
func (valset ValidatorSet) Dissociate(ctx sdk.Context, base sdk.ValAddress, assoc sdk.ValAddress) bool {
|
||||
if len(base) != valset.addrLen || len(assoc) != valset.addrLen {
|
||||
return false
|
||||
|
@ -90,6 +92,7 @@ func (valset ValidatorSet) Dissociate(ctx sdk.Context, base sdk.ValAddress, asso
|
|||
}
|
||||
|
||||
// Associations returns all associated addresses with a validator
|
||||
// nolint: unparam
|
||||
func (valset ValidatorSet) Associations(ctx sdk.Context, base sdk.ValAddress) (res []sdk.ValAddress) {
|
||||
res = make([]sdk.ValAddress, valset.maxAssoc)
|
||||
iter := sdk.KVStorePrefixIterator(valset.store, GetAssocPrefix(base))
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import fileinput
|
||||
import re
|
||||
|
||||
# This script goes through the provided file, and replaces any " \#<number>",
|
||||
# with the valid mark down formatted link to it. e.g.
|
||||
# " [\#number](https://github.com/cosmos/cosmos-sdk/issues/<number>)
|
||||
# Note that if the number is for a PR, github will auto-redirect you when you click the link.
|
||||
# It is safe to run the script multiple times in succession.
|
||||
#
|
||||
# Example usage $ python3 linkify_changelog.py ../PENDING.md
|
||||
for line in fileinput.input(inplace=1):
|
||||
line = re.sub(r"\s\\#([0-9]*)", r" [\\#\1](https://github.com/cosmos/cosmos-sdk/issues/\1)", line.rstrip())
|
||||
print(line)
|
|
@ -344,6 +344,7 @@ func readOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey {
|
|||
|
||||
// writeGenesisFile creates and writes the genesis configuration to disk. An
|
||||
// error is returned if building or writing the configuration to file fails.
|
||||
// nolint: unparam
|
||||
func writeGenesisFile(cdc *wire.Codec, genesisFile, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error {
|
||||
genDoc := tmtypes.GenesisDoc{
|
||||
ChainID: chainID,
|
||||
|
|
|
@ -84,6 +84,7 @@ func startStandAlone(ctx *Context, appCreator AppCreator) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// nolint: unparam
|
||||
func startInProcess(ctx *Context, appCreator AppCreator) (*node.Node, error) {
|
||||
cfg := ctx.Config
|
||||
home := cfg.RootDir
|
||||
|
|
|
@ -20,7 +20,7 @@ const (
|
|||
|
||||
// load the iavl store
|
||||
func LoadIAVLStore(db dbm.DB, id CommitID, pruning sdk.PruningStrategy) (CommitStore, error) {
|
||||
tree := iavl.NewVersionedTree(db, defaultIAVLCacheSize)
|
||||
tree := iavl.NewMutableTree(db, defaultIAVLCacheSize)
|
||||
_, err := tree.LoadVersion(id.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -40,7 +40,7 @@ var _ Queryable = (*iavlStore)(nil)
|
|||
type iavlStore struct {
|
||||
|
||||
// The underlying tree.
|
||||
tree *iavl.VersionedTree
|
||||
tree *iavl.MutableTree
|
||||
|
||||
// How many old versions we hold onto.
|
||||
// A value of 0 means keep no recent states.
|
||||
|
@ -56,7 +56,8 @@ type iavlStore struct {
|
|||
}
|
||||
|
||||
// CONTRACT: tree should be fully loaded.
|
||||
func newIAVLStore(tree *iavl.VersionedTree, numRecent int64, storeEvery int64) *iavlStore {
|
||||
// nolint: unparam
|
||||
func newIAVLStore(tree *iavl.MutableTree, numRecent int64, storeEvery int64) *iavlStore {
|
||||
st := &iavlStore{
|
||||
tree: tree,
|
||||
numRecent: numRecent,
|
||||
|
@ -167,16 +168,16 @@ func (st *iavlStore) Gas(meter GasMeter, config GasConfig) KVStore {
|
|||
|
||||
// Implements KVStore.
|
||||
func (st *iavlStore) Iterator(start, end []byte) Iterator {
|
||||
return newIAVLIterator(st.tree.Tree(), start, end, true)
|
||||
return newIAVLIterator(st.tree.ImmutableTree, start, end, true)
|
||||
}
|
||||
|
||||
// Implements KVStore.
|
||||
func (st *iavlStore) ReverseIterator(start, end []byte) Iterator {
|
||||
return newIAVLIterator(st.tree.Tree(), start, end, false)
|
||||
return newIAVLIterator(st.tree.ImmutableTree, start, end, false)
|
||||
}
|
||||
|
||||
// Handle gatest the latest height, if height is 0
|
||||
func getHeight(tree *iavl.VersionedTree, req abci.RequestQuery) int64 {
|
||||
func getHeight(tree *iavl.MutableTree, req abci.RequestQuery) int64 {
|
||||
height := req.Height
|
||||
if height == 0 {
|
||||
latest := tree.Version64()
|
||||
|
@ -255,7 +256,7 @@ func (st *iavlStore) Query(req abci.RequestQuery) (res abci.ResponseQuery) {
|
|||
// Implements Iterator.
|
||||
type iavlIterator struct {
|
||||
// Underlying store
|
||||
tree *iavl.Tree
|
||||
tree *iavl.ImmutableTree
|
||||
|
||||
// Domain
|
||||
start, end []byte
|
||||
|
@ -286,7 +287,7 @@ var _ Iterator = (*iavlIterator)(nil)
|
|||
// newIAVLIterator will create a new iavlIterator.
|
||||
// CONTRACT: Caller must release the iavlIterator, as each one creates a new
|
||||
// goroutine.
|
||||
func newIAVLIterator(tree *iavl.Tree, start, end []byte, ascending bool) *iavlIterator {
|
||||
func newIAVLIterator(tree *iavl.ImmutableTree, start, end []byte, ascending bool) *iavlIterator {
|
||||
iter := &iavlIterator{
|
||||
tree: tree,
|
||||
start: cp(start),
|
||||
|
|
|
@ -29,8 +29,8 @@ var (
|
|||
)
|
||||
|
||||
// make a tree and save it
|
||||
func newTree(t *testing.T, db dbm.DB) (*iavl.VersionedTree, CommitID) {
|
||||
tree := iavl.NewVersionedTree(db, cacheSize)
|
||||
func newTree(t *testing.T, db dbm.DB) (*iavl.MutableTree, CommitID) {
|
||||
tree := iavl.NewMutableTree(db, cacheSize)
|
||||
for k, v := range treeData {
|
||||
tree.Set([]byte(k), []byte(v))
|
||||
}
|
||||
|
@ -325,7 +325,7 @@ type pruneState struct {
|
|||
|
||||
func testPruning(t *testing.T, numRecent int64, storeEvery int64, states []pruneState) {
|
||||
db := dbm.NewMemDB()
|
||||
tree := iavl.NewVersionedTree(db, cacheSize)
|
||||
tree := iavl.NewMutableTree(db, cacheSize)
|
||||
iavlStore := newIAVLStore(tree, numRecent, storeEvery)
|
||||
for step, state := range states {
|
||||
for _, ver := range state.stored {
|
||||
|
@ -344,7 +344,7 @@ func testPruning(t *testing.T, numRecent int64, storeEvery int64, states []prune
|
|||
|
||||
func TestIAVLNoPrune(t *testing.T) {
|
||||
db := dbm.NewMemDB()
|
||||
tree := iavl.NewVersionedTree(db, cacheSize)
|
||||
tree := iavl.NewMutableTree(db, cacheSize)
|
||||
iavlStore := newIAVLStore(tree, numRecent, int64(1))
|
||||
nextVersion(iavlStore)
|
||||
for i := 1; i < 100; i++ {
|
||||
|
@ -359,7 +359,7 @@ func TestIAVLNoPrune(t *testing.T) {
|
|||
|
||||
func TestIAVLPruneEverything(t *testing.T) {
|
||||
db := dbm.NewMemDB()
|
||||
tree := iavl.NewVersionedTree(db, cacheSize)
|
||||
tree := iavl.NewMutableTree(db, cacheSize)
|
||||
iavlStore := newIAVLStore(tree, int64(0), int64(0))
|
||||
nextVersion(iavlStore)
|
||||
for i := 1; i < 100; i++ {
|
||||
|
@ -377,7 +377,7 @@ func TestIAVLPruneEverything(t *testing.T) {
|
|||
|
||||
func TestIAVLStoreQuery(t *testing.T) {
|
||||
db := dbm.NewMemDB()
|
||||
tree := iavl.NewVersionedTree(db, cacheSize)
|
||||
tree := iavl.NewMutableTree(db, cacheSize)
|
||||
iavlStore := newIAVLStore(tree, numRecent, storeEvery)
|
||||
|
||||
k1, v1 := []byte("key1"), []byte("val1")
|
||||
|
@ -468,7 +468,7 @@ func TestIAVLStoreQuery(t *testing.T) {
|
|||
func BenchmarkIAVLIteratorNext(b *testing.B) {
|
||||
db := dbm.NewMemDB()
|
||||
treeSize := 1000
|
||||
tree := iavl.NewVersionedTree(db, cacheSize)
|
||||
tree := iavl.NewMutableTree(db, cacheSize)
|
||||
for i := 0; i < treeSize; i++ {
|
||||
key := cmn.RandBytes(4)
|
||||
value := cmn.RandBytes(50)
|
||||
|
|
|
@ -2,10 +2,12 @@ package store
|
|||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tendermint/iavl"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
"testing"
|
||||
"github.com/tendermint/tendermint/libs/db"
|
||||
)
|
||||
|
||||
func TestVerifyMultiStoreCommitInfo(t *testing.T) {
|
||||
|
@ -91,7 +93,7 @@ func TestVerifyMultiStoreCommitInfo(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestVerifyRangeProof(t *testing.T) {
|
||||
tree := iavl.NewTree(nil, 0)
|
||||
tree := iavl.NewMutableTree(db.NewMemDB(), 0)
|
||||
|
||||
rand := cmn.NewRand()
|
||||
rand.Seed(0) // for determinism
|
||||
|
@ -100,7 +102,7 @@ func TestVerifyRangeProof(t *testing.T) {
|
|||
tree.Set(key, []byte(rand.Str(8)))
|
||||
}
|
||||
|
||||
root := tree.Hash()
|
||||
root := tree.WorkingHash()
|
||||
|
||||
key := []byte{0x32}
|
||||
val, proof, err := tree.GetWithProof(key)
|
||||
|
|
|
@ -66,7 +66,7 @@ func testPrefixStore(t *testing.T, baseStore KVStore, prefix []byte) {
|
|||
|
||||
func TestIAVLStorePrefix(t *testing.T) {
|
||||
db := dbm.NewMemDB()
|
||||
tree := iavl.NewVersionedTree(db, cacheSize)
|
||||
tree := iavl.NewMutableTree(db, cacheSize)
|
||||
iavlStore := newIAVLStore(tree, numRecent, storeEvery)
|
||||
|
||||
testPrefixStore(t, iavlStore, []byte("test"))
|
||||
|
|
|
@ -179,6 +179,7 @@ func (tkv *TraceKVStore) CacheWrapWithTrace(_ io.Writer, _ TraceContext) CacheWr
|
|||
|
||||
// writeOperation writes a KVStore operation to the underlying io.Writer as
|
||||
// JSON-encoded data where the key/value pair is base64 encoded.
|
||||
// nolint: errcheck
|
||||
func writeOperation(w io.Writer, op operation, tc TraceContext, key, value []byte) {
|
||||
traceOp := traceOperation{
|
||||
Operation: op,
|
||||
|
|
|
@ -156,8 +156,8 @@ func TestTestTraceKVStoreIterator(t *testing.T) {
|
|||
iterator := store.Iterator(nil, nil)
|
||||
|
||||
s, e := iterator.Domain()
|
||||
require.Equal(t, []uint8([]byte(nil)), s)
|
||||
require.Equal(t, []uint8([]byte(nil)), e)
|
||||
require.Equal(t, []byte(nil), s)
|
||||
require.Equal(t, []byte(nil), e)
|
||||
|
||||
testCases := []struct {
|
||||
expectedKey []byte
|
||||
|
@ -212,8 +212,8 @@ func TestTestTraceKVStoreReverseIterator(t *testing.T) {
|
|||
iterator := store.ReverseIterator(nil, nil)
|
||||
|
||||
s, e := iterator.Domain()
|
||||
require.Equal(t, []uint8([]byte(nil)), s)
|
||||
require.Equal(t, []uint8([]byte(nil)), e)
|
||||
require.Equal(t, []byte(nil), s)
|
||||
require.Equal(t, []byte(nil), e)
|
||||
|
||||
testCases := []struct {
|
||||
expectedKey []byte
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
|
||||
// ExecuteT executes the command, pipes any input to STDIN and return STDOUT,
|
||||
// logging STDOUT/STDERR to t.
|
||||
// nolint: errcheck
|
||||
func ExecuteT(t *testing.T, cmd, input string) (out string) {
|
||||
t.Log("Running", cmn.Cyan(cmd))
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ INEFFASSIGN_CHECK := $(shell command -v ineffassign 2> /dev/null)
|
|||
MISSPELL_CHECK := $(shell command -v misspell 2> /dev/null)
|
||||
ERRCHECK_CHECK := $(shell command -v errcheck 2> /dev/null)
|
||||
UNPARAM_CHECK := $(shell command -v unparam 2> /dev/null)
|
||||
GOCYCLO_CHECK := $(shell command -v gocyclo 2> /dev/null)
|
||||
# GOCYCLO_CHECK := $(shell command -v gocyclo 2> /dev/null)
|
||||
|
||||
check_tools:
|
||||
ifndef DEP_CHECK
|
||||
|
@ -126,12 +126,12 @@ else
|
|||
@echo "Installing unparam"
|
||||
go get -v $(UNPARAM)
|
||||
endif
|
||||
ifdef GOCYCLO_CHECK
|
||||
@echo "gocyclo is already installed. Run 'make update_tools' to update."
|
||||
else
|
||||
@echo "Installing gocyclo"
|
||||
go get -v $(GOCYCLO)
|
||||
endif
|
||||
# ifdef GOCYCLO_CHECK
|
||||
# @echo "gocyclo is already installed. Run 'make update_tools' to update."
|
||||
# else
|
||||
# @echo "Installing gocyclo"
|
||||
# go get -v $(GOCYCLO)
|
||||
# endif
|
||||
|
||||
update_tools:
|
||||
@echo "Updating dep"
|
||||
|
@ -153,8 +153,8 @@ update_dev_tools:
|
|||
go get -u -v $(ERRCHECK)
|
||||
@echo "Updating unparam"
|
||||
go get -u -v $(UNPARAM)
|
||||
@echo "Updating goyclo"
|
||||
go get -u -v $(GOCYCLO)
|
||||
# @echo "Updating goyclo"
|
||||
# go get -u -v $(GOCYCLO)
|
||||
|
||||
# To avoid unintended conflicts with file names, always add to .PHONY
|
||||
# unless there is a reason not to.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"Linters": {
|
||||
"vet": "go tool vet -composites=false :PATH:LINE:MESSAGE"
|
||||
},
|
||||
"Enable": ["golint", "vet", "ineffassign", "unparam", "unconvert", "misspell", "gocyclo"],
|
||||
"Enable": ["golint", "vet", "ineffassign", "unparam", "unconvert", "misspell"],
|
||||
"Deadline": "500s",
|
||||
"Vendor": true,
|
||||
"Cyclo": 11
|
||||
|
|
|
@ -133,6 +133,7 @@ func (aa AccAddress) String() string {
|
|||
}
|
||||
|
||||
// Format implements the fmt.Formatter interface.
|
||||
// nolint: errcheck
|
||||
func (aa AccAddress) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 's':
|
||||
|
@ -247,6 +248,7 @@ func (va ValAddress) String() string {
|
|||
}
|
||||
|
||||
// Format implements the fmt.Formatter interface.
|
||||
// nolint: errcheck
|
||||
func (va ValAddress) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 's':
|
||||
|
@ -361,6 +363,7 @@ func (ca ConsAddress) String() string {
|
|||
}
|
||||
|
||||
// Format implements the fmt.Formatter interface.
|
||||
// nolint: errcheck
|
||||
func (ca ConsAddress) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 's':
|
||||
|
|
|
@ -30,6 +30,7 @@ type Context struct {
|
|||
}
|
||||
|
||||
// create a new context
|
||||
// nolint: unparam
|
||||
func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, logger log.Logger) Context {
|
||||
c := Context{
|
||||
Context: context.Background(),
|
||||
|
|
|
@ -219,6 +219,7 @@ func (err *sdkError) WithDefaultCodespace(cs CodespaceType) Error {
|
|||
}
|
||||
|
||||
// Implements ABCIError.
|
||||
// nolint: errcheck
|
||||
func (err *sdkError) TraceSDK(format string, args ...interface{}) Error {
|
||||
err.Trace(1, format, args...)
|
||||
return err
|
||||
|
|
|
@ -30,6 +30,7 @@ func GetAccountDecoder(cdc *wire.Codec) auth.AccountDecoder {
|
|||
|
||||
// GetAccountCmd returns a query account that will display the state of the
|
||||
// account at a given address.
|
||||
// nolint: unparam
|
||||
func GetAccountCmd(storeName string, cdc *wire.Codec, decoder auth.AccountDecoder) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "account [address]",
|
||||
|
|
|
@ -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
|
||||
// it is signed. For use in the CLI.
|
||||
type StdSignMsg struct {
|
||||
ChainID string
|
||||
AccountNumber int64
|
||||
Sequence int64
|
||||
Fee StdFee
|
||||
Msgs []sdk.Msg
|
||||
Memo string
|
||||
ChainID string `json:"chain_id"`
|
||||
AccountNumber int64 `json:"account_number"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
Fee StdFee `json:"fee"`
|
||||
Msgs []sdk.Msg `json:"msgs"`
|
||||
Memo string `json:"memo"`
|
||||
}
|
||||
|
||||
// get message bytes
|
||||
|
|
|
@ -68,6 +68,9 @@ func SendTxCmd(cdc *wire.Codec) *cobra.Command {
|
|||
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
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})
|
||||
},
|
||||
|
|
|
@ -107,6 +107,11 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLICo
|
|||
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})
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
// SimulateSingleInputMsgSend tests and runs a single msg send, with one input and one output, where both
|
||||
// accounts already exist.
|
||||
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)
|
||||
fromAddr := sdk.AccAddress(fromKey.PubKey().Address())
|
||||
toKey := simulation.RandomKey(r, keys)
|
||||
|
@ -58,7 +58,7 @@ func SimulateSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operation
|
|||
Inputs: []bank.Input{bank.NewInput(fromAddr, 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")
|
||||
|
||||
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
|
||||
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))
|
||||
initialOutputAddrCoins := make([]sdk.Coins, len(msg.Outputs))
|
||||
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
|
||||
fmt.Println(res)
|
||||
fmt.Println(log)
|
||||
t.FailNow()
|
||||
tb.FailNow()
|
||||
}
|
||||
|
||||
for i := 0; i < len(msg.Inputs); i++ {
|
||||
terminalInputCoins := mapper.GetAccount(ctx, msg.Inputs[i].Address).GetCoins()
|
||||
require.Equal(t,
|
||||
require.Equal(tb,
|
||||
initialInputAddrCoins[i].Minus(msg.Inputs[i].Coins),
|
||||
terminalInputCoins,
|
||||
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++ {
|
||||
terminalOutputCoins := mapper.GetAccount(ctx, msg.Outputs[i].Address).GetCoins()
|
||||
require.Equal(t,
|
||||
initialOutputAddrCoins[i].Plus(msg.Outputs[i].Coins),
|
||||
terminalOutputCoins,
|
||||
fmt.Sprintf("Output #%d had an incorrect amount of coins\n%s", i, log),
|
||||
)
|
||||
if !terminalOutputCoins.IsEqual(initialOutputAddrCoins[i].Plus(msg.Outputs[i].Coins)) {
|
||||
tb.Fatalf("Output #%d had an incorrect amount of coins\n%s", i, log)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -99,12 +99,15 @@ $ gaiacli gov submit-proposal --title="Test Proposal" --description="My awesome
|
|||
}
|
||||
|
||||
msg := gov.NewMsgSubmitProposal(proposal.Title, proposal.Description, proposalType, fromAddr, amount)
|
||||
|
||||
err = msg.ValidateBasic()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||
}
|
||||
|
||||
// Build and sign the transaction, then broadcast to Tendermint
|
||||
// proposalID must be returned, and it is a part of response.
|
||||
cliCtx.PrintResponse = true
|
||||
|
@ -177,12 +180,15 @@ func GetCmdDeposit(cdc *wire.Codec) *cobra.Command {
|
|||
}
|
||||
|
||||
msg := gov.NewMsgDeposit(depositerAddr, proposalID, amount)
|
||||
|
||||
err = msg.ValidateBasic()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||
}
|
||||
|
||||
// Build and sign the transaction, then broadcast to a Tendermint
|
||||
// node.
|
||||
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)
|
||||
|
||||
err = msg.ValidateBasic()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||
}
|
||||
|
||||
fmt.Printf("Vote[Voter:%s,ProposalID:%d,Option:%s]",
|
||||
voterAddr.String(), msg.ProposalID, msg.Option.String(),
|
||||
)
|
||||
|
|
|
@ -96,6 +96,12 @@ func signAndBuild(w http.ResponseWriter, r *http.Request, cliCtx context.CLICont
|
|||
}
|
||||
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})
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
|
||||
|
|
|
@ -132,6 +132,7 @@ func (vo VoteOption) String() string {
|
|||
}
|
||||
|
||||
// For Printf / Sprintf, returns bech32 when using %s
|
||||
// nolint: errcheck
|
||||
func (vo VoteOption) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 's':
|
||||
|
|
|
@ -209,6 +209,7 @@ func (keeper Keeper) activateVotingPeriod(ctx sdk.Context, proposal Proposal) {
|
|||
// Procedures
|
||||
|
||||
// Returns the current Deposit Procedure from the global param store
|
||||
// nolint: errcheck
|
||||
func (keeper Keeper) GetDepositProcedure(ctx sdk.Context) DepositProcedure {
|
||||
var depositProcedure 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
|
||||
// nolint: errcheck
|
||||
func (keeper Keeper) GetVotingProcedure(ctx sdk.Context) VotingProcedure {
|
||||
var votingProcedure 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
|
||||
// nolint: errcheck
|
||||
func (keeper Keeper) GetTallyingProcedure(ctx sdk.Context) TallyingProcedure {
|
||||
var tallyingProcedure TallyingProcedure
|
||||
keeper.ps.Get(ctx, ParamStoreKeyTallyingProcedure, &tallyingProcedure)
|
||||
return tallyingProcedure
|
||||
}
|
||||
|
||||
// nolint: errcheck
|
||||
func (keeper Keeper) setDepositProcedure(ctx sdk.Context, depositProcedure DepositProcedure) {
|
||||
keeper.ps.Set(ctx, ParamStoreKeyDepositProcedure, &depositProcedure)
|
||||
}
|
||||
|
||||
// nolint: errcheck
|
||||
func (keeper Keeper) setVotingProcedure(ctx sdk.Context, votingProcedure VotingProcedure) {
|
||||
keeper.ps.Set(ctx, ParamStoreKeyVotingProcedure, &votingProcedure)
|
||||
}
|
||||
|
||||
// nolint: errcheck
|
||||
func (keeper Keeper) setTallyingProcedure(ctx sdk.Context, tallyingProcedure TallyingProcedure) {
|
||||
keeper.ps.Set(ctx, ParamStoreKeyTallyingProcedure, &tallyingProcedure)
|
||||
}
|
||||
|
|
|
@ -12,11 +12,11 @@ const MsgType = "gov"
|
|||
//-----------------------------------------------------------
|
||||
// MsgSubmitProposal
|
||||
type MsgSubmitProposal struct {
|
||||
Title string // Title of the proposal
|
||||
Description string // Description of the proposal
|
||||
ProposalType ProposalKind // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}
|
||||
Proposer sdk.AccAddress // Address of the proposer
|
||||
InitialDeposit sdk.Coins // Initial deposit paid by sender. Must be strictly positive.
|
||||
Title string `json:"title"` // Title of the proposal
|
||||
Description string `json:"description"` // Description of the proposal
|
||||
ProposalType ProposalKind `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}
|
||||
Proposer sdk.AccAddress `json:"proposer"` // Address of the proposer
|
||||
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 {
|
||||
|
|
|
@ -188,6 +188,7 @@ func (pt ProposalKind) String() string {
|
|||
}
|
||||
|
||||
// For Printf / Sprintf, returns bech32 when using %s
|
||||
// nolint: errcheck
|
||||
func (pt ProposalKind) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 's':
|
||||
|
@ -290,6 +291,7 @@ func (status ProposalStatus) String() string {
|
|||
}
|
||||
|
||||
// For Printf / Sprintf, returns bech32 when using %s
|
||||
// nolint: errcheck
|
||||
func (status ProposalStatus) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 's':
|
||||
|
|
|
@ -36,6 +36,7 @@ type QueryProposalParams struct {
|
|||
ProposalID int64
|
||||
}
|
||||
|
||||
// nolint: unparam
|
||||
func queryProposal(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
||||
var params QueryProposalParams
|
||||
err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms)
|
||||
|
@ -61,6 +62,7 @@ type QueryDepositParams struct {
|
|||
Depositer sdk.AccAddress
|
||||
}
|
||||
|
||||
// nolint: unparam
|
||||
func queryDeposit(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
||||
var params QueryDepositParams
|
||||
err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms)
|
||||
|
@ -82,6 +84,7 @@ type QueryVoteParams struct {
|
|||
Voter sdk.AccAddress
|
||||
}
|
||||
|
||||
// nolint: unparam
|
||||
func queryVote(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
||||
var params QueryVoteParams
|
||||
err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms)
|
||||
|
@ -102,6 +105,7 @@ type QueryDepositsParams struct {
|
|||
ProposalID int64
|
||||
}
|
||||
|
||||
// nolint: unparam
|
||||
func queryDeposits(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
||||
var params QueryDepositParams
|
||||
err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms)
|
||||
|
@ -129,6 +133,7 @@ type QueryVotesParams struct {
|
|||
ProposalID int64
|
||||
}
|
||||
|
||||
// nolint: unparam
|
||||
func queryVotes(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
||||
var params QueryVotesParams
|
||||
err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms)
|
||||
|
@ -160,6 +165,7 @@ type QueryProposalsParams struct {
|
|||
NumLatestProposals int64
|
||||
}
|
||||
|
||||
// nolint: unparam
|
||||
func queryProposals(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
||||
var params QueryProposalsParams
|
||||
err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms)
|
||||
|
@ -181,6 +187,7 @@ type QueryTallyParams struct {
|
|||
ProposalID int64
|
||||
}
|
||||
|
||||
// nolint: unparam
|
||||
func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
||||
// TODO: Dependant on #1914
|
||||
|
||||
|
|
|
@ -5,8 +5,6 @@ import (
|
|||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
|
@ -23,24 +21,15 @@ const (
|
|||
// SimulateMsgSubmitProposal simulates a msg Submit Proposal
|
||||
// Note: Currently doesn't ensure that the proposal txt is in JSON form
|
||||
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) {
|
||||
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,
|
||||
)
|
||||
require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
||||
handler := gov.NewHandler(k)
|
||||
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOps []simulation.FutureOperation, err sdk.Error) {
|
||||
msg := simulationCreateMsgSubmitProposal(tb, r, keys, log)
|
||||
ctx, write := ctx.CacheContext()
|
||||
result := gov.NewHandler(k)(ctx, msg)
|
||||
result := handler(ctx, msg)
|
||||
if result.IsOK() {
|
||||
// Update pool to keep invariants
|
||||
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)
|
||||
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
|
||||
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)
|
||||
addr := sdk.AccAddress(key.PubKey().Address())
|
||||
proposalID, ok := randomProposalID(r, k, ctx)
|
||||
|
@ -61,7 +67,9 @@ func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
|||
}
|
||||
deposit := randomDeposit(r)
|
||||
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()
|
||||
result := gov.NewHandler(k)(ctx, msg)
|
||||
if result.IsOK() {
|
||||
|
@ -78,8 +86,9 @@ func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
|||
}
|
||||
|
||||
// SimulateMsgVote
|
||||
// nolint: unparam
|
||||
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)
|
||||
addr := sdk.AccAddress(key.PubKey().Address())
|
||||
proposalID, ok := randomProposalID(r, k, ctx)
|
||||
|
@ -88,7 +97,9 @@ func SimulateMsgVote(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
|||
}
|
||||
option := randomVotingOption(r)
|
||||
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()
|
||||
result := gov.NewHandler(k)(ctx, msg)
|
||||
if result.IsOK() {
|
||||
|
|
|
@ -43,6 +43,9 @@ func IBCTransferCmd(cdc *wire.Codec) *cobra.Command {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||
}
|
||||
|
||||
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||
},
|
||||
|
|
|
@ -163,6 +163,7 @@ func query(node string, key []byte, storeName string) (res []byte, err error) {
|
|||
return context.NewCLIContext().WithNodeURI(node).QueryStore(key, storeName)
|
||||
}
|
||||
|
||||
// nolint: unparam
|
||||
func (c relayCommander) broadcastTx(seq int64, node string, tx []byte) error {
|
||||
_, err := context.NewCLIContext().WithNodeURI(node).BroadcastTx(tx)
|
||||
return err
|
||||
|
|
|
@ -98,6 +98,11 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.C
|
|||
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})
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
|
||||
|
|
|
@ -22,11 +22,11 @@ func init() {
|
|||
// IBCPacket defines a piece of data that can be send between two separate
|
||||
// blockchains.
|
||||
type IBCPacket struct {
|
||||
SrcAddr sdk.AccAddress
|
||||
DestAddr sdk.AccAddress
|
||||
Coins sdk.Coins
|
||||
SrcChain string
|
||||
DestChain string
|
||||
SrcAddr sdk.AccAddress `json:"src_addr"`
|
||||
DestAddr sdk.AccAddress `json:"dest_addr"`
|
||||
Coins sdk.Coins `json:"coins"`
|
||||
SrcChain string `json:"src_chain"`
|
||||
DestChain string `json:"dest_chain"`
|
||||
}
|
||||
|
||||
func NewIBCPacket(srcAddr sdk.AccAddress, destAddr sdk.AccAddress, coins sdk.Coins,
|
||||
|
|
|
@ -86,6 +86,7 @@ func (app *App) CompleteSetup(newKeys []*sdk.KVStoreKey) error {
|
|||
}
|
||||
|
||||
// InitChainer performs custom logic for initialization.
|
||||
// nolint: errcheck
|
||||
func (app *App) InitChainer(ctx sdk.Context, _ abci.RequestInitChain) abci.ResponseInitChain {
|
||||
// Load the genesis accounts
|
||||
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
|
||||
// provided addresses and coin denominations.
|
||||
// nolint: errcheck
|
||||
func RandomSetGenesis(r *rand.Rand, app *App, addrs []sdk.AccAddress, denoms []string) {
|
||||
accts := make([]auth.Account, len(addrs), len(addrs))
|
||||
randCoinIntervals := []BigInterval{
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"os"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -16,7 +17,6 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// 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 tests an application by running the provided
|
||||
// operations, testing the provided invariants, but using the provided seed.
|
||||
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]++
|
||||
}
|
||||
|
||||
func initChain(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress, setups []RandSetup, app *baseapp.BaseApp,
|
||||
appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage) (validators map[string]mockValidator) {
|
||||
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 {
|
||||
validators[string(validator.Address)] = mockValidator{validator, GetMemberOfInitialState(r, initialLivenessWeightings)}
|
||||
}
|
||||
|
@ -64,85 +40,161 @@ func SimulateFromSeed(
|
|||
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}
|
||||
opCount := 0
|
||||
|
||||
var pastTimes []time.Time
|
||||
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
|
||||
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
|
||||
pastTimes = append(pastTimes, header.Time)
|
||||
pastSigningValidators = append(pastSigningValidators, request.LastCommitInfo.Validators)
|
||||
|
||||
// Run the BeginBlock handler
|
||||
app.BeginBlock(request)
|
||||
log = updateLog(testingMode, log, "BeginBlock")
|
||||
|
||||
log += "\nBeginBlock"
|
||||
|
||||
// Make sure invariants hold at beginning of block
|
||||
AssertAllInvariants(t, app, invariants, log)
|
||||
if testingMode {
|
||||
// Make sure invariants hold at beginning of block
|
||||
AssertAllInvariants(t, app, invariants, log)
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
thisBlockSize -= numQueuedOpsRan
|
||||
for j := 0; j < thisBlockSize; j++ {
|
||||
logUpdate, futureOps, err := ops[r.Intn(len(ops))](t, r, app, ctx, keys, log, event)
|
||||
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++
|
||||
}
|
||||
log, operations := blockSimulator(thisBlockSize, r, app, ctx, keys, log, header)
|
||||
opCount += operations
|
||||
|
||||
res := app.EndBlock(abci.RequestEndBlock{})
|
||||
header.Height++
|
||||
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"
|
||||
|
||||
// Make sure invariants hold at end of block
|
||||
AssertAllInvariants(t, app, invariants, log)
|
||||
|
||||
if testingMode {
|
||||
// Make sure invariants hold at end of block
|
||||
AssertAllInvariants(t, app, invariants, log)
|
||||
}
|
||||
if commit {
|
||||
app.Commit()
|
||||
}
|
||||
|
||||
// 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
|
||||
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)
|
||||
}
|
||||
|
||||
// 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.
|
||||
func queueOperations(queuedOperations map[int][]Operation, futureOperations []FutureOperation) {
|
||||
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) {
|
||||
updatedLog = log
|
||||
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.
|
||||
// If a need arises for us to support queued messages to queue more messages, this can
|
||||
// be changed.
|
||||
logUpdate, _, err := queuedOps[i](t, r, app, ctx, privKeys, updatedLog, event)
|
||||
updatedLog += "\n" + logUpdate
|
||||
require.Nil(t, err, updatedLog)
|
||||
logUpdate, _, err := queuedOps[i](tb, r, app, ctx, privKeys, updatedLog, event)
|
||||
updatedLog = fmt.Sprintf("%s\n%s", updatedLog, logUpdate)
|
||||
if err != nil {
|
||||
fmt.Fprint(os.Stderr, updatedLog)
|
||||
tb.FailNow()
|
||||
}
|
||||
}
|
||||
delete(queueOperations, height)
|
||||
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
|
||||
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 {
|
||||
if len(validators) == 0 {
|
||||
return abci.RequestBeginBlock{Header: header}
|
||||
|
@ -220,6 +277,7 @@ func RandomRequestBeginBlock(t *testing.T, r *rand.Rand, validators map[string]m
|
|||
}
|
||||
i++
|
||||
}
|
||||
// TODO: Determine capacity before allocation
|
||||
evidence := make([]abci.Evidence, 0)
|
||||
// Anything but the first block
|
||||
if len(pastTimes) > 0 {
|
||||
|
@ -264,11 +322,20 @@ func AssertAllInvariants(t *testing.T, app *baseapp.BaseApp, tests []Invariant,
|
|||
}
|
||||
|
||||
// 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 {
|
||||
switch {
|
||||
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")
|
||||
delete(current, string(update.PubKey.Data))
|
||||
default:
|
||||
|
|
|
@ -23,7 +23,7 @@ type (
|
|||
// Operations can optionally provide a list of "FutureOperations" to run later
|
||||
// These will be ran at the beginning of the corresponding block.
|
||||
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),
|
||||
) (action string, futureOperations []FutureOperation, err sdk.Error)
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ func NewKeeper(cdc *wire.Codec, key sdk.StoreKey) Keeper {
|
|||
}
|
||||
|
||||
// InitKeeper constructs a new Keeper with initial parameters
|
||||
// nolint: errcheck
|
||||
func InitKeeper(ctx sdk.Context, cdc *wire.Codec, key sdk.StoreKey, params ...interface{}) Keeper {
|
||||
if len(params)%2 != 0 {
|
||||
panic("Odd params list length for InitKeeper")
|
||||
|
|
|
@ -15,6 +15,7 @@ func ActivatedParamKey(ty string) string {
|
|||
}
|
||||
|
||||
// InitGenesis stores activated type to param store
|
||||
// nolint: errcheck
|
||||
func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) {
|
||||
for _, ty := range data.ActivatedTypes {
|
||||
k.set(ctx, ActivatedParamKey(ty), true)
|
||||
|
|
|
@ -33,7 +33,9 @@ func GetCmdUnjail(cdc *wire.Codec) *cobra.Command {
|
|||
}
|
||||
|
||||
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})
|
||||
},
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Cod
|
|||
}
|
||||
|
||||
// http request handler to query signing info
|
||||
// nolint: unparam
|
||||
func signingInfoHandlerFn(cliCtx context.CLIContext, storeName string, cdc *wire.Codec) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
|
|
@ -99,6 +99,11 @@ func unjailRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLI
|
|||
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})
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own validator address")
|
||||
|
|
|
@ -16,15 +16,15 @@ func TestCannotUnjailUnlessJailed(t *testing.T) {
|
|||
slh := NewHandler(keeper)
|
||||
amtInt := int64(100)
|
||||
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)
|
||||
require.True(t, got.IsOK())
|
||||
stake.EndBlocker(ctx, sk)
|
||||
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
|
||||
got = slh(ctx, NewMsgUnjail(sdk.ValAddress(addr)))
|
||||
got = slh(ctx, NewMsgUnjail(addr))
|
||||
require.False(t, got.IsOK(), "allowed unjail of non-jailed validator")
|
||||
require.Equal(t, sdk.ToABCICode(DefaultCodespace, CodeValidatorNotJailed), got.Code)
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ func TestJailedValidatorDelegations(t *testing.T) {
|
|||
// create a validator
|
||||
amount := int64(10)
|
||||
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)
|
||||
got := stake.NewHandler(stakeKeeper)(ctx, msgCreateVal)
|
||||
|
|
|
@ -27,12 +27,12 @@ func TestHandleDoubleSign(t *testing.T) {
|
|||
sk = sk.WithValidatorHooks(keeper.ValidatorHooks())
|
||||
amtInt := int64(100)
|
||||
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())
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
keeper.AddValidators(ctx, validatorUpdates)
|
||||
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
|
||||
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)
|
||||
|
||||
// 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
|
||||
sk.Unjail(ctx, val)
|
||||
// power should be reduced
|
||||
require.Equal(
|
||||
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))})
|
||||
|
||||
|
@ -55,7 +55,7 @@ func TestHandleDoubleSign(t *testing.T) {
|
|||
keeper.handleDoubleSign(ctx, val.Address(), 0, time.Unix(0, 0), amtInt)
|
||||
require.Equal(
|
||||
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)
|
||||
sh := stake.NewHandler(sk)
|
||||
slh := NewHandler(keeper)
|
||||
got := sh(ctx, newTestMsgCreateValidator(sdk.ValAddress(addr), val, amt))
|
||||
got := sh(ctx, newTestMsgCreateValidator(addr, val, amt))
|
||||
require.True(t, got.IsOK())
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
keeper.AddValidators(ctx, validatorUpdates)
|
||||
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()))
|
||||
require.False(t, found)
|
||||
require.Equal(t, int64(0), info.StartHeight)
|
||||
|
@ -165,7 +165,7 @@ func TestHandleAbsentValidator(t *testing.T) {
|
|||
validator, _ := sk.GetValidatorByPubKey(ctx, val)
|
||||
require.Equal(t, sdk.Bonded, validator.GetStatus())
|
||||
pool := sk.GetPool(ctx)
|
||||
require.Equal(t, int64(amtInt), pool.BondedTokens.RoundInt64())
|
||||
require.Equal(t, amtInt, pool.BondedTokens.RoundInt64())
|
||||
|
||||
// 501st block missed
|
||||
ctx = ctx.WithBlockHeight(height)
|
||||
|
@ -180,12 +180,12 @@ func TestHandleAbsentValidator(t *testing.T) {
|
|||
require.Equal(t, sdk.Unbonding, validator.GetStatus())
|
||||
|
||||
// unrevocation should fail prior to jail expiration
|
||||
got = slh(ctx, NewMsgUnjail(sdk.ValAddress(addr)))
|
||||
got = slh(ctx, NewMsgUnjail(addr))
|
||||
require.False(t, got.IsOK())
|
||||
|
||||
// unrevocation should succeed after jail expiration
|
||||
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())
|
||||
|
||||
// validator should be rebonded now
|
||||
|
@ -195,7 +195,7 @@ func TestHandleAbsentValidator(t *testing.T) {
|
|||
// validator should have been slashed
|
||||
pool = sk.GetPool(ctx)
|
||||
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
|
||||
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address()))
|
||||
|
@ -235,12 +235,12 @@ func TestHandleNewValidator(t *testing.T) {
|
|||
ctx, ck, sk, _, keeper := createTestInput(t)
|
||||
addr, val, amt := addrs[0], pks[0], int64(100)
|
||||
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())
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
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, 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
|
||||
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()))
|
||||
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(1), info.SignedBlocksCounter)
|
||||
require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil)
|
||||
|
@ -273,7 +273,7 @@ func TestHandleAlreadyJailed(t *testing.T) {
|
|||
amtInt := int64(100)
|
||||
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
|
||||
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())
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
keeper.AddValidators(ctx, validatorUpdates)
|
||||
|
@ -296,7 +296,7 @@ func TestHandleAlreadyJailed(t *testing.T) {
|
|||
require.Equal(t, sdk.Unbonding, validator.GetStatus())
|
||||
|
||||
// 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
|
||||
ctx = ctx.WithBlockHeight(height)
|
||||
|
@ -304,6 +304,6 @@ func TestHandleAlreadyJailed(t *testing.T) {
|
|||
|
||||
// validator should not have been slashed twice
|
||||
validator, _ = sk.GetValidatorByPubKey(ctx, val)
|
||||
require.Equal(t, int64(amtInt-1), validator.GetTokens().RoundInt64())
|
||||
require.Equal(t, amtInt-1, validator.GetTokens().RoundInt64())
|
||||
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@ import (
|
|||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
|
@ -17,11 +15,13 @@ import (
|
|||
|
||||
// SimulateMsgUnjail
|
||||
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)
|
||||
address := sdk.ValAddress(key.PubKey().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()
|
||||
result := slashing.NewHandler(k)(ctx, msg)
|
||||
if result.IsOK() {
|
||||
|
|
|
@ -17,12 +17,12 @@ func TestBeginBlocker(t *testing.T) {
|
|||
addr, pk, amt := addrs[2], pks[2], sdk.NewInt(100)
|
||||
|
||||
// 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())
|
||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||
keeper.AddValidators(ctx, validatorUpdates)
|
||||
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{
|
||||
Address: pk.Address(),
|
||||
|
|
|
@ -77,7 +77,9 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command {
|
|||
} else {
|
||||
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
|
||||
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)
|
||||
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||
}
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
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)
|
||||
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||
}
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
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)
|
||||
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||
}
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
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)
|
||||
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||
}
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
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)
|
||||
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||
}
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||
},
|
||||
|
@ -409,6 +426,9 @@ func GetCmdCompleteUnbonding(cdc *wire.Codec) *cobra.Command {
|
|||
|
||||
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
|
||||
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||
},
|
||||
|
|
|
@ -297,6 +297,11 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex
|
|||
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})
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
|
||||
|
|
|
@ -163,6 +163,7 @@ func getValidators(validatorKVs []sdk.KVPair, cdc *wire.Codec) ([]types.BechVali
|
|||
}
|
||||
|
||||
// gets all Bech32 validators from a key
|
||||
// nolint: unparam
|
||||
func getBech32Validators(storeName string, cliCtx context.CLIContext, cdc *wire.Codec) (
|
||||
validators []types.BechValidator, httpStatusCode int, errMsg string, err error) {
|
||||
|
||||
|
|
|
@ -430,7 +430,7 @@ func TestIncrementsMsgUnbond(t *testing.T) {
|
|||
initBond,
|
||||
}
|
||||
for _, c := range errorCases {
|
||||
unbondShares := sdk.NewDec(int64(c))
|
||||
unbondShares := sdk.NewDec(c)
|
||||
msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares)
|
||||
got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper)
|
||||
require.False(t, got.IsOK(), "expected unbond msg to fail")
|
||||
|
|
|
@ -68,6 +68,7 @@ func GetValidatorsByPowerIndexKey(validator types.Validator, pool types.Pool) []
|
|||
|
||||
// get the power ranking of a validator
|
||||
// NOTE the larger values are of higher value
|
||||
// nolint: unparam
|
||||
func getValidatorPowerRank(validator types.Validator, pool types.Pool) []byte {
|
||||
|
||||
potentialPower := validator.Tokens
|
||||
|
|
|
@ -203,6 +203,7 @@ func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation ty
|
|||
// the unbonding delegation had enough stake to slash
|
||||
// (the amount actually slashed may be less if there's
|
||||
// insufficient stake remaining)
|
||||
// nolint: unparam
|
||||
func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, redelegation types.Redelegation,
|
||||
infractionHeight int64, slashFactor sdk.Dec) (slashAmount sdk.Dec) {
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package keeper
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"container/list"
|
||||
"fmt"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
@ -11,6 +12,19 @@ import (
|
|||
"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
|
||||
func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator types.Validator, found bool) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
|
@ -18,6 +32,28 @@ func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator ty
|
|||
if value == nil {
|
||||
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)
|
||||
return validator, true
|
||||
}
|
||||
|
@ -336,6 +372,7 @@ func (k Keeper) updateForJailing(ctx sdk.Context, oldFound bool, oldValidator, n
|
|||
return newValidator
|
||||
}
|
||||
|
||||
// nolint: unparam
|
||||
func (k Keeper) getPowerIncreasing(ctx sdk.Context, oldFound bool, oldValidator, newValidator types.Validator) bool {
|
||||
if oldFound && oldValidator.BondedTokens().LT(newValidator.BondedTokens()) {
|
||||
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
|
||||
// nolint: unparam
|
||||
func (k Keeper) bondIncrement(ctx sdk.Context, oldFound bool, oldValidator,
|
||||
newValidator types.Validator) (height int64, intraTxCounter int16) {
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ func AllInvariants(ck bank.Keeper, k stake.Keeper, am auth.AccountMapper) simula
|
|||
}
|
||||
|
||||
// SupplyInvariants checks that the total supply reflects all held loose tokens, bonded tokens, and unbonding delegations
|
||||
// nolint: unparam
|
||||
func SupplyInvariants(ck bank.Keeper, k stake.Keeper, am auth.AccountMapper) simulation.Invariant {
|
||||
return func(t *testing.T, app *baseapp.BaseApp, log string) {
|
||||
ctx := app.NewContext(false, abci.Header{})
|
||||
|
|
|
@ -5,8 +5,6 @@ import (
|
|||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
|
@ -19,9 +17,8 @@ import (
|
|||
|
||||
// SimulateMsgCreateValidator
|
||||
func SimulateMsgCreateValidator(m auth.AccountMapper, k 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) {
|
||||
handler := stake.NewHandler(k)
|
||||
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
description := stake.Description{
|
||||
|
@ -44,9 +41,11 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation
|
|||
PubKey: pubkey,
|
||||
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()
|
||||
result := stake.NewHandler(k)(ctx, msg)
|
||||
result := handler(ctx, msg)
|
||||
if result.IsOK() {
|
||||
write()
|
||||
}
|
||||
|
@ -59,9 +58,8 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation
|
|||
|
||||
// SimulateMsgEditValidator
|
||||
func SimulateMsgEditValidator(k 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) {
|
||||
handler := stake.NewHandler(k)
|
||||
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||
|
||||
description := stake.Description{
|
||||
Moniker: simulation.RandStringOfLength(r, 10),
|
||||
|
@ -76,9 +74,11 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
|
|||
Description: description,
|
||||
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()
|
||||
result := stake.NewHandler(k)(ctx, msg)
|
||||
result := handler(ctx, msg)
|
||||
if result.IsOK() {
|
||||
write()
|
||||
}
|
||||
|
@ -90,9 +90,8 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
|
|||
|
||||
// SimulateMsgDelegate
|
||||
func SimulateMsgDelegate(m auth.AccountMapper, k 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) {
|
||||
handler := stake.NewHandler(k)
|
||||
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
validatorKey := simulation.RandomKey(r, keys)
|
||||
|
@ -111,9 +110,11 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat
|
|||
ValidatorAddr: validatorAddress,
|
||||
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()
|
||||
result := stake.NewHandler(k)(ctx, msg)
|
||||
result := handler(ctx, msg)
|
||||
if result.IsOK() {
|
||||
write()
|
||||
}
|
||||
|
@ -125,9 +126,8 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat
|
|||
|
||||
// SimulateMsgBeginUnbonding
|
||||
func SimulateMsgBeginUnbonding(m auth.AccountMapper, k 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) {
|
||||
handler := stake.NewHandler(k)
|
||||
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
validatorKey := simulation.RandomKey(r, keys)
|
||||
|
@ -146,9 +146,11 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.
|
|||
ValidatorAddr: validatorAddress,
|
||||
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()
|
||||
result := stake.NewHandler(k)(ctx, msg)
|
||||
result := handler(ctx, msg)
|
||||
if result.IsOK() {
|
||||
write()
|
||||
}
|
||||
|
@ -160,9 +162,8 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.
|
|||
|
||||
// SimulateMsgCompleteUnbonding
|
||||
func SimulateMsgCompleteUnbonding(k 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) {
|
||||
handler := stake.NewHandler(k)
|
||||
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||
|
||||
validatorKey := simulation.RandomKey(r, keys)
|
||||
validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address())
|
||||
|
@ -172,9 +173,11 @@ func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
|
|||
DelegatorAddr: delegatorAddress,
|
||||
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()
|
||||
result := stake.NewHandler(k)(ctx, msg)
|
||||
result := handler(ctx, msg)
|
||||
if result.IsOK() {
|
||||
write()
|
||||
}
|
||||
|
@ -186,9 +189,8 @@ func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
|
|||
|
||||
// SimulateMsgBeginRedelegate
|
||||
func SimulateMsgBeginRedelegate(m auth.AccountMapper, k 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) {
|
||||
handler := stake.NewHandler(k)
|
||||
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||
|
||||
denom := k.GetParams(ctx).BondDenom
|
||||
sourceValidatorKey := simulation.RandomKey(r, keys)
|
||||
|
@ -211,9 +213,11 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation
|
|||
ValidatorDstAddr: destValidatorAddress,
|
||||
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()
|
||||
result := stake.NewHandler(k)(ctx, msg)
|
||||
result := handler(ctx, msg)
|
||||
if result.IsOK() {
|
||||
write()
|
||||
}
|
||||
|
@ -225,9 +229,8 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation
|
|||
|
||||
// SimulateMsgCompleteRedelegate
|
||||
func SimulateMsgCompleteRedelegate(k 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) {
|
||||
handler := stake.NewHandler(k)
|
||||
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||
|
||||
validatorSrcKey := simulation.RandomKey(r, keys)
|
||||
validatorSrcAddress := sdk.ValAddress(validatorSrcKey.PubKey().Address())
|
||||
|
@ -240,9 +243,11 @@ func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation {
|
|||
ValidatorSrcAddr: validatorSrcAddress,
|
||||
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()
|
||||
result := stake.NewHandler(k)(ctx, msg)
|
||||
result := handler(ctx, msg)
|
||||
if result.IsOK() {
|
||||
write()
|
||||
}
|
||||
|
@ -253,6 +258,7 @@ func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation {
|
|||
}
|
||||
|
||||
// Setup
|
||||
// nolint: errcheck
|
||||
func Setup(mapp *mock.App, k stake.Keeper) simulation.RandSetup {
|
||||
return func(r *rand.Rand, privKeys []crypto.PrivKey) {
|
||||
ctx := mapp.NewContext(false, abci.Header{})
|
||||
|
|
|
@ -23,7 +23,7 @@ func TestDelegationEqual(t *testing.T) {
|
|||
ok := d1.Equal(d2)
|
||||
require.True(t, ok)
|
||||
|
||||
d2.ValidatorAddr = sdk.ValAddress(addr3)
|
||||
d2.ValidatorAddr = addr3
|
||||
d2.Shares = sdk.NewDec(200)
|
||||
|
||||
ok = d1.Equal(d2)
|
||||
|
@ -57,7 +57,7 @@ func TestUnbondingDelegationEqual(t *testing.T) {
|
|||
ok := ud1.Equal(ud2)
|
||||
require.True(t, ok)
|
||||
|
||||
ud2.ValidatorAddr = sdk.ValAddress(addr3)
|
||||
ud2.ValidatorAddr = addr3
|
||||
|
||||
ud2.MinTime = time.Unix(20*20*2, 0)
|
||||
ok = ud1.Equal(ud2)
|
||||
|
|
Loading…
Reference in New Issue