Merge remote-tracking branch 'origin/develop' into rigel/fee-distribution

This commit is contained in:
rigelrozanski 2018-10-15 02:43:36 -04:00
commit 5de0c9a1f8
62 changed files with 1304 additions and 1078 deletions

View File

@ -56,6 +56,7 @@ jobs:
name: Get metalinter
command: |
export PATH="$GOBIN:$PATH"
make get_tools
make get_dev_tools
- run:
name: Lint source

View File

@ -6,6 +6,10 @@ BUILD_FLAGS = -tags "${BUILD_TAGS}" -ldflags "-X github.com/cosmos/cosmos-sdk/ve
GCC := $(shell command -v gcc 2> /dev/null)
LEDGER_ENABLED ?= true
UNAME_S := $(shell uname -s)
GOTOOLS = \
github.com/golang/dep/cmd/dep \
github.com/alecthomas/gometalinter \
github.com/rakyll/statik
all: get_tools get_vendor_deps install install_examples install_cosmos-sdk-cli test_lint test
########################################
@ -91,22 +95,27 @@ dist:
### Tools & dependencies
check_tools:
cd tools && $(MAKE) check_tools
check_dev_tools:
cd tools && $(MAKE) check_dev_tools
@# https://stackoverflow.com/a/25668869
@echo "Found tools: $(foreach tool,$(notdir $(GOTOOLS)),\
$(if $(shell which $(tool)),$(tool),$(error "No $(tool) in PATH")))"
update_tools:
cd tools && $(MAKE) update_tools
@echo "--> Updating tools to correct version"
./scripts/get_tools.sh
update_dev_tools:
cd tools && $(MAKE) update_dev_tools
@echo "--> Downloading linters (this may take awhile)"
$(GOPATH)/src/github.com/alecthomas/gometalinter/scripts/install.sh -b $(GOBIN)
go get -u github.com/tendermint/lint/golint
get_tools:
cd tools && $(MAKE) get_tools
@echo "--> Installing tools"
./scripts/get_tools.sh
get_dev_tools:
cd tools && $(MAKE) get_dev_tools
@echo "--> Downloading linters (this may take awhile)"
$(GOPATH)/src/github.com/alecthomas/gometalinter/scripts/install.sh -b $(GOBIN)
go get github.com/tendermint/lint/golint
get_vendor_deps:
@echo "--> Generating vendor directory via dep ensure"
@ -181,8 +190,8 @@ test_cover:
@export VERSION=$(VERSION); bash tests/test_cover.sh
test_lint:
gometalinter.v2 --config=tools/gometalinter.json ./...
!(gometalinter.v2 --exclude /usr/lib/go/src/ --exclude client/lcd/statik/statik.go --disable-all --enable='errcheck' --vendor ./... | grep -v "client/")
gometalinter --config=tools/gometalinter.json ./...
!(gometalinter --exclude /usr/lib/go/src/ --exclude client/lcd/statik/statik.go --exclude 'vendor/*' --disable-all --enable='errcheck' --vendor ./... | grep -v "client/")
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -d -s
dep status >> /dev/null
!(grep -n branch Gopkg.toml)

View File

@ -69,6 +69,7 @@ BREAKING CHANGES
* [x/staking] \#2244 staking now holds a consensus-address-index instead of a consensus-pubkey-index
* [x/staking] \#2236 more distribution hooks for distribution
* [x/stake] \#2394 Split up UpdateValidator into distinct state transitions applied only in EndBlock
* [x/stake] \#2412 Added an unbonding validator queue to EndBlock to automatically update validator.Status when finished Unbonding
* Tendermint
* Update tendermint version from v0.23.0 to v0.25.0, notable changes
@ -170,6 +171,7 @@ IMPROVEMENTS
calls which includes dynamic consumption of value length.
* [types/decimal] \#2378 - Added truncate functionality to decimal
* [client] [\#1184](https://github.com/cosmos/cosmos-sdk/issues/1184) Remove unused `client/tx/sign.go`.
* [tools] \#2464 Lock binary dependencies to a specific version
* Tendermint

View File

@ -43,7 +43,7 @@ func generateSelfSignedCert(host string) (certBytes []byte, priv *ecdsa.PrivateK
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
IsCA: true,
IsCA: true,
}
hosts := strings.Split(host, ",")
for _, h := range hosts {

View File

@ -93,21 +93,44 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
)
// add handlers
app.feeCollectionKeeper = auth.NewFeeCollectionKeeper(app.cdc, app.keyFeeCollection)
app.bankKeeper = bank.NewBaseKeeper(app.accountMapper)
app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams)
app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.tkeyStake,
app.bankKeeper, app.RegisterCodespace(stake.DefaultCodespace))
app.distrKeeper = distr.NewKeeper(app.cdc, app.keyDistr, app.tkeyDistr,
app.feeCollectionKeeper = auth.NewFeeCollectionKeeper(
app.cdc,
app.keyFeeCollection,
)
app.paramsKeeper = params.NewKeeper(
app.cdc,
app.keyParams, app.tkeyParams,
)
app.stakeKeeper = stake.NewKeeper(
app.cdc,
app.keyStake, app.tkeyStake,
app.bankKeeper, app.paramsKeeper.Subspace(stake.DefaultParamspace),
app.RegisterCodespace(stake.DefaultCodespace),
)
app.distrKeeper = distr.NewKeeper(
app.cdc,
app.keyDistr, app.tkeyDistr,
app.paramsKeeper.Setter(), app.bankKeeper, app.stakeKeeper,
app.feeCollectionKeeper, app.RegisterCodespace(stake.DefaultCodespace))
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper,
app.paramsKeeper.Getter(), app.RegisterCodespace(slashing.DefaultCodespace))
app.govKeeper = gov.NewKeeper(app.cdc, app.keyGov, app.paramsKeeper.Setter(),
app.bankKeeper, app.stakeKeeper, app.RegisterCodespace(gov.DefaultCodespace))
app.feeCollectionKeeper,
app.RegisterCodespace(stake.DefaultCodespace),
)
app.slashingKeeper = slashing.NewKeeper(
app.cdc,
app.keySlashing,
app.stakeKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace),
app.RegisterCodespace(slashing.DefaultCodespace),
)
app.govKeeper = gov.NewKeeper(
app.cdc,
app.keyGov,
app.paramsKeeper, app.paramsKeeper.Subspace(gov.DefaultParamspace), app.bankKeeper, app.stakeKeeper,
app.RegisterCodespace(gov.DefaultCodespace),
)
// register the staking hooks
app.stakeKeeper = app.stakeKeeper.WithHooks(NewHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks()))
app.stakeKeeper = app.stakeKeeper.WithHooks(
NewHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks()))
// register message routes
app.Router().
@ -207,7 +230,7 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
}
// load the address to pubkey map
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.StakeData)
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.SlashingData, genesisState.StakeData)
gov.InitGenesis(ctx, app.govKeeper, genesisState.GovData)
distr.InitGenesis(ctx, app.distrKeeper, genesisState.DistrData)

View File

@ -6,6 +6,7 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/stake"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/libs/db"
@ -21,8 +22,9 @@ func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
}
genesisState := GenesisState{
Accounts: genaccs,
StakeData: stake.DefaultGenesisState(),
Accounts: genaccs,
StakeData: stake.DefaultGenesisState(),
SlashingData: slashing.DefaultGenesisState(),
}
stateBytes, err := codec.MarshalJSONIndent(gapp.cdc, genesisState)

View File

@ -13,6 +13,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/stake"
"github.com/spf13/pflag"
@ -32,10 +33,11 @@ var (
// State to Unmarshal
type GenesisState struct {
Accounts []GenesisAccount `json:"accounts"`
StakeData stake.GenesisState `json:"stake"`
DistrData distr.GenesisState `json:"distr_data"`
GovData gov.GenesisState `json:"gov"`
Accounts []GenesisAccount `json:"accounts"`
StakeData stake.GenesisState `json:"stake"`
DistrData distr.GenesisState `json:"distr"`
GovData gov.GenesisState `json:"gov"`
SlashingData slashing.GenesisState `json:"slashing"`
}
// GenesisAccount doesn't need pubkey or sequence
@ -170,6 +172,8 @@ func GaiaAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (genesisStat
// start with the default staking genesis state
stakeData := stake.DefaultGenesisState()
slashingData := slashing.DefaultGenesisState()
// get genesis flag account information
genaccs := make([]GenesisAccount, len(appGenTxs))
for i, appGenTx := range appGenTxs {
@ -192,10 +196,11 @@ func GaiaAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (genesisStat
// create the final app state
genesisState = GenesisState{
Accounts: genaccs,
StakeData: stakeData,
DistrData: distr.DefaultGenesisState(),
GovData: gov.DefaultGenesisState(),
Accounts: genaccs,
StakeData: stakeData,
DistrData: distr.DefaultGenesisState(),
GovData: gov.DefaultGenesisState(),
SlashingData: slashingData,
}
return

View File

@ -19,6 +19,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/gov"
govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation"
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
"github.com/cosmos/cosmos-sdk/x/slashing"
slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation"
stake "github.com/cosmos/cosmos-sdk/x/stake"
stakesim "github.com/cosmos/cosmos-sdk/x/stake/simulation"
@ -55,7 +56,9 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
}
// Default genesis state
govGenesis := gov.DefaultGenesisState()
stakeGenesis := stake.DefaultGenesisState()
slashingGenesis := slashing.DefaultGenesisState()
var validators []stake.Validator
var delegations []stake.Delegation
@ -81,10 +84,11 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
stakeGenesis.Params.InflationMin = sdk.NewDec(0)
genesis := GenesisState{
Accounts: genesisAccounts,
StakeData: stakeGenesis,
DistrData: distr.DefaultGenesisWithValidators(valAddrs),
GovData: gov.DefaultGenesisState(),
Accounts: genesisAccounts,
StakeData: stakeGenesis,
DistrData: distr.DefaultGenesisWithValidators(valAddrs),
SlashingData: slashingGenesis,
GovData: govGenesis,
}
// Marshal genesis

View File

@ -7,6 +7,7 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/stake"
tmtypes "github.com/tendermint/tendermint/types"
)
@ -69,8 +70,9 @@ func NewTestGaiaAppGenState(
}
return GenesisState{
Accounts: genAccs,
StakeData: stakeData,
GovData: gov.DefaultGenesisState(),
Accounts: genAccs,
StakeData: stakeData,
SlashingData: slashing.DefaultGenesisState(),
GovData: gov.DefaultGenesisState(),
}, nil
}

View File

@ -135,6 +135,7 @@ type GaiaApp struct {
tkeyStake *sdk.TransientStoreKey
keySlashing *sdk.KVStoreKey
keyParams *sdk.KVStoreKey
tkeyParams *sdk.TransientStoreKey
// Manage getting and setting accounts
accountMapper auth.AccountMapper
@ -161,6 +162,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseAp
tkeyStake: sdk.NewTransientStoreKey("transient_stake"),
keySlashing: sdk.NewKVStoreKey("slashing"),
keyParams: sdk.NewKVStoreKey("params"),
tkeyParams: sdk.NewTransientStoreKey("transient_params"),
}
// define the accountMapper
@ -172,9 +174,9 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseAp
// add handlers
app.bankKeeper = bank.NewBaseKeeper(app.accountMapper)
app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams)
app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.tkeyStake, app.bankKeeper, app.RegisterCodespace(stake.DefaultCodespace))
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.paramsKeeper.Getter(), app.RegisterCodespace(slashing.DefaultCodespace))
app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams, app.tkeyParams)
app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.tkeyStake, app.bankKeeper, app.paramsKeeper.Subspace(stake.DefaultParamspace), app.RegisterCodespace(stake.DefaultCodespace))
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace), app.RegisterCodespace(slashing.DefaultCodespace))
// register message routes
app.Router().
@ -186,7 +188,8 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseAp
app.SetBeginBlocker(app.BeginBlocker)
app.SetEndBlocker(app.EndBlocker)
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper))
app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyStake, app.keySlashing)
app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyStake, app.keySlashing, app.keyParams)
app.MountStore(app.tkeyParams, sdk.StoreTypeTransient)
err := app.LoadLatestVersion(app.keyMain)
if err != nil {
cmn.Exit(err.Error())
@ -252,6 +255,8 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468 // return sdk.ErrGenesisParse("").TraceCause(err, "")
}
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.SlashingData, genesisState.StakeData)
return abci.ResponseInitChain{
Validators: validators,
}

View File

@ -1,5 +1,20 @@
# End-Block
## Unbonding Validator Queue
For all unbonding validators that have finished their unbonding period, this switches their validator.Status
from sdk.Unbonding to sdk.Unbonded
```golang
validatorQueue(currTime time.Time):
// unbonding validators are in ordered queue from oldest to newest
for all unbondingValidators whose CompleteTime < currTime:
validator = GetValidator(unbondingValidator.ValidatorAddr)
validator.Status = sdk.Bonded
SetValidator(unbondingValidator)
return
```
## Validator Set Changes
The Tendermint validator set may be updated by state transitions that run at

49
scripts/get_tools.sh Executable file
View File

@ -0,0 +1,49 @@
#!/usr/bin/env bash
set -e
# This file downloads all of the binary dependencies we have, and checks out a
# specific git hash.
#
# repos it installs:
# github.com/golang/dep/cmd/dep
# gopkg.in/alecthomas/gometalinter.v2
# github.com/rakyll/statiik
## check if GOPATH is set
if [ -z ${GOPATH+x} ]; then
echo "please set GOPATH (https://github.com/golang/go/wiki/SettingGOPATH)"
exit 1
fi
mkdir -p "$GOPATH/src/github.com"
cd "$GOPATH/src/github.com" || exit 1
installFromGithub() {
repo=$1
commit=$2
# optional
subdir=$3
echo "--> Installing $repo ($commit)..."
if [ ! -d "$repo" ]; then
mkdir -p "$repo"
git clone "https://github.com/$repo.git" "$repo"
fi
if [ ! -z ${subdir+x} ] && [ ! -d "$repo/$subdir" ]; then
echo "ERROR: no such directory $repo/$subdir"
exit 1
fi
pushd "$repo" && \
git fetch origin && \
git checkout -q "$commit" && \
if [ ! -z ${subdir+x} ]; then cd "$subdir" || exit 1; fi && \
go install && \
if [ ! -z ${subdir+x} ]; then cd - || exit 1; fi && \
popd || exit 1
echo "--> Done"
echo ""
}
installFromGithub golang/dep 22125cfaa6ddc71e145b1535d4b7ee9744fefff2 cmd/dep
## gometalinter v2.0.11
installFromGithub alecthomas/gometalinter 17a7ffa42374937bfecabfb8d2efbd4db0c26741
installFromGithub rakyll/statik v0.1.5

View File

@ -13,13 +13,13 @@ import (
func newGasKVStore() KVStore {
meter := sdk.NewGasMeter(1000)
mem := dbStoreAdapter{dbm.NewMemDB()}
return NewGasKVStore(meter, sdk.DefaultGasConfig(), mem)
return NewGasKVStore(meter, sdk.KVGasConfig(), mem)
}
func TestGasKVStoreBasic(t *testing.T) {
mem := dbStoreAdapter{dbm.NewMemDB()}
meter := sdk.NewGasMeter(1000)
st := NewGasKVStore(meter, sdk.DefaultGasConfig(), mem)
st := NewGasKVStore(meter, sdk.KVGasConfig(), mem)
require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty")
st.Set(keyFmt(1), valFmt(1))
require.Equal(t, valFmt(1), st.Get(keyFmt(1)))
@ -31,7 +31,7 @@ func TestGasKVStoreBasic(t *testing.T) {
func TestGasKVStoreIterator(t *testing.T) {
mem := dbStoreAdapter{dbm.NewMemDB()}
meter := sdk.NewGasMeter(1000)
st := NewGasKVStore(meter, sdk.DefaultGasConfig(), mem)
st := NewGasKVStore(meter, sdk.KVGasConfig(), mem)
require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty")
require.Empty(t, st.Get(keyFmt(2)), "Expected `key2` to be empty")
st.Set(keyFmt(1), valFmt(1))
@ -55,14 +55,14 @@ func TestGasKVStoreIterator(t *testing.T) {
func TestGasKVStoreOutOfGasSet(t *testing.T) {
mem := dbStoreAdapter{dbm.NewMemDB()}
meter := sdk.NewGasMeter(0)
st := NewGasKVStore(meter, sdk.DefaultGasConfig(), mem)
st := NewGasKVStore(meter, sdk.KVGasConfig(), mem)
require.Panics(t, func() { st.Set(keyFmt(1), valFmt(1)) }, "Expected out-of-gas")
}
func TestGasKVStoreOutOfGasIterator(t *testing.T) {
mem := dbStoreAdapter{dbm.NewMemDB()}
meter := sdk.NewGasMeter(200)
st := NewGasKVStore(meter, sdk.DefaultGasConfig(), mem)
st := NewGasKVStore(meter, sdk.KVGasConfig(), mem)
st.Set(keyFmt(1), valFmt(1))
iterator := st.Iterator(nil, nil)
iterator.Next()

View File

@ -26,6 +26,9 @@ func cloneAppend(bz []byte, tail []byte) (res []byte) {
}
func (s prefixStore) key(key []byte) (res []byte) {
if key == nil {
panic("nil key on prefixStore")
}
res = cloneAppend(s.prefix, key)
return
}

View File

@ -17,7 +17,7 @@ type kvpair struct {
value []byte
}
func setRandomKVPairs(t *testing.T, store KVStore) []kvpair {
func genRandomKVPairs(t *testing.T) []kvpair {
kvps := make([]kvpair, 20)
for i := 0; i < 20; i++ {
@ -25,17 +25,26 @@ func setRandomKVPairs(t *testing.T, store KVStore) []kvpair {
rand.Read(kvps[i].key)
kvps[i].value = make([]byte, 32)
rand.Read(kvps[i].value)
store.Set(kvps[i].key, kvps[i].value)
}
return kvps
}
func setRandomKVPairs(t *testing.T, store KVStore) []kvpair {
kvps := genRandomKVPairs(t)
for _, kvp := range kvps {
store.Set(kvp.key, kvp.value)
}
return kvps
}
func testPrefixStore(t *testing.T, baseStore KVStore, prefix []byte) {
prefixStore := baseStore.Prefix(prefix)
prefixPrefixStore := prefixStore.Prefix([]byte("prefix"))
require.Panics(t, func() { prefixStore.Get(nil) })
require.Panics(t, func() { prefixStore.Set(nil, []byte{}) })
kvps := setRandomKVPairs(t, prefixPrefixStore)
for i := 0; i < 20; i++ {
@ -81,7 +90,7 @@ func TestCacheKVStorePrefix(t *testing.T) {
func TestGasKVStorePrefix(t *testing.T) {
meter := sdk.NewGasMeter(100000000)
mem := dbStoreAdapter{dbm.NewMemDB()}
gasStore := NewGasKVStore(meter, sdk.DefaultGasConfig(), mem)
gasStore := NewGasKVStore(meter, sdk.KVGasConfig(), mem)
testPrefixStore(t, gasStore, []byte("test"))
}
@ -109,6 +118,33 @@ func TestPrefixStoreIterate(t *testing.T) {
pIter.Close()
}
func incFirstByte(bz []byte) {
if bz[0] == byte(255) {
bz[0] = byte(0)
return
}
bz[0]++
}
func TestCloneAppend(t *testing.T) {
kvps := genRandomKVPairs(t)
for _, kvp := range kvps {
bz := cloneAppend(kvp.key, kvp.value)
require.Equal(t, bz, append(kvp.key, kvp.value...))
incFirstByte(bz)
require.NotEqual(t, bz, append(kvp.key, kvp.value...))
bz = cloneAppend(kvp.key, kvp.value)
incFirstByte(kvp.key)
require.NotEqual(t, bz, append(kvp.key, kvp.value...))
bz = cloneAppend(kvp.key, kvp.value)
incFirstByte(kvp.value)
require.NotEqual(t, bz, append(kvp.key, kvp.value...))
}
}
func TestPrefixStoreIteratorEdgeCase(t *testing.T) {
db := dbm.NewMemDB()
baseStore := dbStoreAdapter{db}

View File

@ -1,170 +0,0 @@
all: get_tools
########################################
### DEP
DEP = github.com/golang/dep/cmd/dep
GOLINT = github.com/tendermint/lint/golint
GOMETALINTER = gopkg.in/alecthomas/gometalinter.v2
UNCONVERT = github.com/mdempsky/unconvert
INEFFASSIGN = github.com/gordonklaus/ineffassign
MISSPELL = github.com/client9/misspell/cmd/misspell
ERRCHECK = github.com/kisielk/errcheck
UNPARAM = mvdan.cc/unparam
STATIK = github.com/rakyll/statik
DEP_CHECK := $(shell command -v dep 2> /dev/null)
GOLINT_CHECK := $(shell command -v golint 2> /dev/null)
GOMETALINTER_CHECK := $(shell command -v gometalinter.v2 2> /dev/null)
UNCONVERT_CHECK := $(shell command -v unconvert 2> /dev/null)
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)
STATIK_CHECK := $(shell command -v statik 2> /dev/null)
check_tools:
ifndef DEP_CHECK
@echo "No dep in path. Install with 'make get_tools'."
else
@echo "Found dep in path."
endif
check_dev_tools:
$(MAKE) check_tools
ifndef GOLINT_CHECK
@echo "No golint in path. Install with 'make get_tools'."
else
@echo "Found golint in path."
endif
ifndef GOMETALINTER_CHECK
@echo "No gometalinter in path. Install with 'make get_tools'."
else
@echo "Found gometalinter in path."
endif
ifndef UNCONVERT_CHECK
@echo "No unconvert in path. Install with 'make get_tools'."
else
@echo "Found unconvert in path."
endif
ifndef INEFFASSIGN_CHECK
@echo "No ineffassign in path. Install with 'make get_tools'."
else
@echo "Found ineffassign in path."
endif
ifndef MISSPELL_CHECK
@echo "No misspell in path. Install with 'make get_tools'."
else
@echo "Found misspell in path."
endif
ifndef ERRCHECK_CHECK
@echo "No errcheck in path. Install with 'make get_tools'."
else
@echo "Found errcheck in path."
endif
ifndef UNPARAM_CHECK
@echo "No unparam in path. Install with 'make get_tools'."
else
@echo "Found unparam in path."
endif
ifndef STATIK_CHECK
@echo "No statik in path. Install with 'make get_tools'."
else
@echo "Found statik in path."
endif
get_tools:
ifdef DEP_CHECK
@echo "Dep is already installed. Run 'make update_tools' to update."
else
@echo "Installing dep"
go get -v $(DEP)
endif
ifdef STATIK_CHECK
@echo "Statik is already installed. Run 'make update_tools' to update."
else
@echo "Installing statik"
go version
go get -v $(STATIK)
endif
get_dev_tools:
$(MAKE) get_tools
ifdef GOLINT_CHECK
@echo "Golint is already installed. Run 'make update_tools' to update."
else
@echo "Installing golint"
go get -v $(GOLINT)
endif
ifdef GOMETALINTER_CHECK
@echo "Gometalinter.v2 is already installed. Run 'make update_tools' to update."
else
@echo "Installing gometalinter.v2"
go get -v $(GOMETALINTER)
endif
ifdef UNCONVERT_CHECK
@echo "Unconvert is already installed. Run 'make update_tools' to update."
else
@echo "Installing unconvert"
go get -v $(UNCONVERT)
endif
ifdef INEFFASSIGN_CHECK
@echo "Ineffassign is already installed. Run 'make update_tools' to update."
else
@echo "Installing ineffassign"
go get -v $(INEFFASSIGN)
endif
ifdef MISSPELL_CHECK
@echo "misspell is already installed. Run 'make update_tools' to update."
else
@echo "Installing misspell"
go get -v $(MISSPELL)
endif
ifdef ERRCHECK_CHECK
@echo "errcheck is already installed. Run 'make update_tools' to update."
else
@echo "Installing errcheck"
go get -v $(ERRCHECK)
endif
ifdef UNPARAM_CHECK
@echo "unparam is already installed. Run 'make update_tools' to update."
else
@echo "Installing unparam"
go get -v $(UNPARAM)
endif
ifdef STATIK_CHECK
@echo "statik is already installed. Run 'make update_tools' to update."
else
@echo "Installing statik"
go get -v $(STATIK)
endif
update_tools:
@echo "Updating dep"
go get -u -v $(DEP)
update_dev_tools:
$(MAKE) update_tools
@echo "Updating tendermint/golint"
go get -u -v $(GOLINT)
@echo "Updating gometalinter.v2"
go get -u -v $(GOMETALINTER)
@echo "Updating unconvert"
go get -u -v $(UNCONVERT)
@echo "Updating ineffassign"
go get -u -v $(INEFFASSIGN)
@echo "Updating misspell"
go get -u -v $(MISSPELL)
@echo "Updating errcheck"
go get -u -v $(ERRCHECK)
@echo "Updating unparam"
go get -u -v $(UNPARAM)
@echo "Updating statik"
go get -u -v $(STATIK)
# To avoid unintended conflicts with file names, always add to .PHONY
# unless there is a reason not to.
# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
.PHONY: check_tools get_tools update_tools check_dev_tools get_dev_tools update_dev_tools

View File

@ -6,5 +6,5 @@
"Deadline": "500s",
"Vendor": true,
"Cyclo": 11,
"Exclude": ["/usr/lib/go/src/", "client/lcd/statik/statik.go"]
"Exclude": ["/usr/lib/go/src/", "client/lcd/statik/statik.go", "vendor/*"]
}

View File

@ -32,7 +32,6 @@ 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(),
@ -74,7 +73,7 @@ func (c Context) Value(key interface{}) interface{} {
// KVStore fetches a KVStore from the MultiStore.
func (c Context) KVStore(key StoreKey) KVStore {
return c.multiStore().GetKVStore(key).Gas(c.GasMeter(), cachedDefaultGasConfig)
return c.multiStore().GetKVStore(key).Gas(c.GasMeter(), cachedKVGasConfig)
}
// TransientStore fetches a TransientStore from the MultiStore.
@ -195,7 +194,9 @@ func (c Context) WithProposer(addr ConsAddress) Context {
}
func (c Context) WithBlockHeight(height int64) Context {
return c.withValue(contextKeyBlockHeight, height)
newHeader := c.BlockHeader()
newHeader.Height = height
return c.withValue(contextKeyBlockHeight, height).withValue(contextKeyBlockHeader, newHeader)
}
func (c Context) WithConsensusParams(params *abci.ConsensusParams) Context {

View File

@ -164,15 +164,16 @@ func TestContextWithCustom(t *testing.T) {
meter := types.NewGasMeter(10000)
minFees := types.Coins{types.NewInt64Coin("feeCoin", 1)}
ctx = types.NewContext(nil, header, ischeck, logger).
ctx = types.NewContext(nil, header, ischeck, logger)
require.Equal(t, header, ctx.BlockHeader())
ctx = ctx.
WithBlockHeight(height).
WithChainID(chainid).
WithTxBytes(txbytes).
WithVoteInfos(voteinfos).
WithGasMeter(meter).
WithMinimumFees(minFees)
require.Equal(t, header, ctx.BlockHeader())
require.Equal(t, height, ctx.BlockHeight())
require.Equal(t, chainid, ctx.ChainID())
require.Equal(t, ischeck, ctx.IsCheckTx())

View File

@ -13,7 +13,7 @@ const (
)
var (
cachedDefaultGasConfig = DefaultGasConfig()
cachedKVGasConfig = KVGasConfig()
cachedTransientGasConfig = TransientGasConfig()
)
@ -86,8 +86,8 @@ type GasConfig struct {
IterNextCostFlat Gas
}
// DefaultGasConfig returns a default gas config for KVStores.
func DefaultGasConfig() GasConfig {
// KVGasConfig returns a default gas config for KVStores.
func KVGasConfig() GasConfig {
return GasConfig{
HasCost: 10,
DeleteCost: 10,
@ -103,5 +103,5 @@ func DefaultGasConfig() GasConfig {
// TransientGasConfig returns a default gas config for TransientStores.
func TransientGasConfig() GasConfig {
// TODO: define gasconfig for transient stores
return DefaultGasConfig()
return KVGasConfig()
}

View File

@ -19,9 +19,9 @@ func NewValidatorDistInfo(operatorAddr sdk.ValAddress, currentHeight int64) Vali
return ValidatorDistInfo{
OperatorAddr: operatorAddr,
FeePoolWithdrawalHeight: currentHeight,
Pool: DecCoins{},
PoolCommission: DecCoins{},
DelAccum: NewTotalAccum(currentHeight),
Pool: DecCoins{},
PoolCommission: DecCoins{},
DelAccum: NewTotalAccum(currentHeight),
}
}

View File

@ -7,17 +7,34 @@ import (
"github.com/cosmos/cosmos-sdk/x/params"
)
// nolint
// Parameter store default namestore
const (
ParamStoreKeyDepositProcedure = "gov/depositprocedure"
ParamStoreKeyVotingProcedure = "gov/votingprocedure"
ParamStoreKeyTallyingProcedure = "gov/tallyingprocedure"
DefaultParamspace = "gov"
)
// Parameter store key
var (
ParamStoreKeyDepositProcedure = []byte("depositprocedure")
ParamStoreKeyVotingProcedure = []byte("votingprocedure")
ParamStoreKeyTallyingProcedure = []byte("tallyingprocedure")
)
// Type declaration for parameters
func ParamTypeTable() params.TypeTable {
return params.NewTypeTable(
ParamStoreKeyDepositProcedure, DepositProcedure{},
ParamStoreKeyVotingProcedure, VotingProcedure{},
ParamStoreKeyTallyingProcedure, TallyingProcedure{},
)
}
// Governance Keeper
type Keeper struct {
// The reference to the ParamSetter to get and set Global Params
ps params.Setter
// The reference to the Param Keeper to get and set Global Params
paramsKeeper params.Keeper
// The reference to the Paramstore to get and set gov specific params
paramSpace params.Subspace
// The reference to the CoinKeeper to modify balances
ck bank.Keeper
@ -43,15 +60,16 @@ type Keeper struct {
// - depositing funds into proposals, and activating upon sufficient funds being deposited
// - users voting on proposals, with weight proportional to stake in the system
// - and tallying the result of the vote.
func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, ps params.Setter, ck bank.Keeper, ds sdk.DelegationSet, codespace sdk.CodespaceType) Keeper {
func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramsKeeper params.Keeper, paramSpace params.Subspace, ck bank.Keeper, ds sdk.DelegationSet, codespace sdk.CodespaceType) Keeper {
return Keeper{
storeKey: key,
ps: ps,
ck: ck,
ds: ds,
vs: ds.GetValidatorSet(),
cdc: cdc,
codespace: codespace,
storeKey: key,
paramsKeeper: paramsKeeper,
paramSpace: paramSpace.WithTypeTable(ParamTypeTable()),
ck: ck,
ds: ds,
vs: ds.GetValidatorSet(),
cdc: cdc,
codespace: codespace,
}
}
@ -210,7 +228,7 @@ func (keeper Keeper) activateVotingPeriod(ctx sdk.Context, proposal Proposal) {
// nolint: errcheck
func (keeper Keeper) GetDepositProcedure(ctx sdk.Context) DepositProcedure {
var depositProcedure DepositProcedure
keeper.ps.Get(ctx, ParamStoreKeyDepositProcedure, &depositProcedure)
keeper.paramSpace.Get(ctx, ParamStoreKeyDepositProcedure, &depositProcedure)
return depositProcedure
}
@ -218,7 +236,7 @@ func (keeper Keeper) GetDepositProcedure(ctx sdk.Context) DepositProcedure {
// nolint: errcheck
func (keeper Keeper) GetVotingProcedure(ctx sdk.Context) VotingProcedure {
var votingProcedure VotingProcedure
keeper.ps.Get(ctx, ParamStoreKeyVotingProcedure, &votingProcedure)
keeper.paramSpace.Get(ctx, ParamStoreKeyVotingProcedure, &votingProcedure)
return votingProcedure
}
@ -226,23 +244,23 @@ func (keeper Keeper) GetVotingProcedure(ctx sdk.Context) VotingProcedure {
// nolint: errcheck
func (keeper Keeper) GetTallyingProcedure(ctx sdk.Context) TallyingProcedure {
var tallyingProcedure TallyingProcedure
keeper.ps.Get(ctx, ParamStoreKeyTallyingProcedure, &tallyingProcedure)
keeper.paramSpace.Get(ctx, ParamStoreKeyTallyingProcedure, &tallyingProcedure)
return tallyingProcedure
}
// nolint: errcheck
func (keeper Keeper) setDepositProcedure(ctx sdk.Context, depositProcedure DepositProcedure) {
keeper.ps.Set(ctx, ParamStoreKeyDepositProcedure, &depositProcedure)
keeper.paramSpace.Set(ctx, ParamStoreKeyDepositProcedure, &depositProcedure)
}
// nolint: errcheck
func (keeper Keeper) setVotingProcedure(ctx sdk.Context, votingProcedure VotingProcedure) {
keeper.ps.Set(ctx, ParamStoreKeyVotingProcedure, &votingProcedure)
keeper.paramSpace.Set(ctx, ParamStoreKeyVotingProcedure, &votingProcedure)
}
// nolint: errcheck
func (keeper Keeper) setTallyingProcedure(ctx sdk.Context, tallyingProcedure TallyingProcedure) {
keeper.ps.Set(ctx, ParamStoreKeyTallyingProcedure, &tallyingProcedure)
keeper.paramSpace.Set(ctx, ParamStoreKeyTallyingProcedure, &tallyingProcedure)
}
// =====================================================

View File

@ -23,21 +23,23 @@ func TestGovWithRandomMessages(t *testing.T) {
bank.RegisterCodec(mapp.Cdc)
gov.RegisterCodec(mapp.Cdc)
mapper := mapp.AccountMapper
bankKeeper := bank.NewBaseKeeper(mapper)
stakeKey := sdk.NewKVStoreKey("stake")
stakeTKey := sdk.NewTransientStoreKey("transient_stake")
stakeKeeper := stake.NewKeeper(mapp.Cdc, stakeKey, stakeTKey, bankKeeper, stake.DefaultCodespace)
paramKey := sdk.NewKVStoreKey("params")
paramKeeper := params.NewKeeper(mapp.Cdc, paramKey)
paramTKey := sdk.NewTransientStoreKey("transient_params")
paramKeeper := params.NewKeeper(mapp.Cdc, paramKey, paramTKey)
stakeKeeper := stake.NewKeeper(mapp.Cdc, stakeKey, stakeTKey, bankKeeper, paramKeeper.Subspace(stake.DefaultParamspace), stake.DefaultCodespace)
govKey := sdk.NewKVStoreKey("gov")
govKeeper := gov.NewKeeper(mapp.Cdc, govKey, paramKeeper.Setter(), bankKeeper, stakeKeeper, gov.DefaultCodespace)
govKeeper := gov.NewKeeper(mapp.Cdc, govKey, paramKeeper, paramKeeper.Subspace(gov.DefaultParamspace), bankKeeper, stakeKeeper, gov.DefaultCodespace)
mapp.Router().AddRoute("gov", gov.NewHandler(govKeeper))
mapp.SetEndBlocker(func(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
gov.EndBlocker(ctx, govKeeper)
return abci.ResponseEndBlock{}
})
err := mapp.CompleteSetup(stakeKey, stakeTKey, paramKey, govKey)
err := mapp.CompleteSetup(stakeKey, stakeTKey, paramKey, paramTKey, govKey)
if err != nil {
panic(err)
}

View File

@ -27,20 +27,22 @@ func getMockApp(t *testing.T, numGenAccs int) (*mock.App, Keeper, stake.Keeper,
RegisterCodec(mapp.Cdc)
keyGlobalParams := sdk.NewKVStoreKey("params")
tkeyGlobalParams := sdk.NewTransientStoreKey("transient_params")
keyStake := sdk.NewKVStoreKey("stake")
tkeyStake := sdk.NewTransientStoreKey("transient_stake")
keyGov := sdk.NewKVStoreKey("gov")
pk := params.NewKeeper(mapp.Cdc, keyGlobalParams)
pk := params.NewKeeper(mapp.Cdc, keyGlobalParams, tkeyGlobalParams)
ck := bank.NewBaseKeeper(mapp.AccountMapper)
sk := stake.NewKeeper(mapp.Cdc, keyStake, tkeyStake, ck, mapp.RegisterCodespace(stake.DefaultCodespace))
keeper := NewKeeper(mapp.Cdc, keyGov, pk.Setter(), ck, sk, DefaultCodespace)
sk := stake.NewKeeper(mapp.Cdc, keyStake, tkeyStake, ck, pk.Subspace(stake.DefaultParamspace), mapp.RegisterCodespace(stake.DefaultCodespace))
keeper := NewKeeper(mapp.Cdc, keyGov, pk, pk.Subspace("testgov"), ck, sk, DefaultCodespace)
mapp.Router().AddRoute("gov", NewHandler(keeper))
mapp.SetEndBlocker(getEndBlocker(keeper))
mapp.SetInitChainer(getInitChainer(mapp, keeper, sk))
require.NoError(t, mapp.CompleteSetup(keyStake, keyGov, keyGlobalParams, tkeyStake))
require.NoError(t, mapp.CompleteSetup(keyStake, tkeyStake, keyGov, keyGlobalParams, tkeyGlobalParams))
genAccs, addrs, pubKeys, privKeys := mock.CreateGenAccounts(numGenAccs, sdk.Coins{sdk.NewInt64Coin("steak", 42)})

85
x/params/doc.go Normal file
View File

@ -0,0 +1,85 @@
package params
/*
Package params provides a globally available parameter store.
There are two main types, Keeper and Space. Space is an isolated namespace for a
paramstore, where keys are prefixed by preconfigured spacename. Keeper has a
permission to access all existing spaces and create new space.
Space can be used by the individual keepers, who needs a private parameter store
that the other keeper are not able to modify. Keeper can be used by the Governance
keeper, who need to modify any parameter in case of the proposal passes.
Basic Usage:
First, declare parameter space and parameter keys for the module. Then include
params.Store in the keeper. Since we prefix the keys with the spacename, it is
recommended to use the same name with the module's.
const (
DefaultParamspace = "mymodule"
)
const (
KeyParameter1 = "myparameter1"
KeyParameter2 = "myparameter2"
)
type Keeper struct {
cdc *wire.Codec
key sdk.StoreKey
ps params.Subspace
}
Pass a params.Store to NewKeeper with DefaultParamSpace (or another)
app.myKeeper = mymodule.NewKeeper(app.paramStore.SubStore(mymodule.DefaultParamspace))
Now we can access to the paramstore using Paramstore Keys
k.ps.Get(KeyParameter1, &param)
k.ps.Set(KeyParameter2, param)
Genesis Usage:
Declare a struct for parameters and make it implement ParamStruct. It will then
be able to be passed to SetFromParamStruct.
type MyParams struct {
Parameter1 uint64
Parameter2 string
}
func (p *MyParams) KeyFieldPairs() params.KeyFieldPairs {
return params.KeyFieldPairs {
{KeyParameter1, &p.Parameter1},
{KeyParameter2, &p.Parameter2},
}
}
func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) {
k.ps.SetFromParamStruct(ctx, &data.params)
}
The method is pointer receiver because there could be a case that we read from
the store and set the result to the struct.
Master Permission Usage:
Keepers that require master permission to the paramstore, such as gov, can take
params.Keeper itself to access all substores(using GetSubstore)
type MasterKeeper struct {
ps params.Store
}
func (k MasterKeeper) SetParam(ctx sdk.Context, space string, key string, param interface{}) {
store, ok := k.ps.GetSubstore(space)
if !ok {
return
}
store.Set(ctx, key, param)
}
*/

View File

@ -1,406 +1,57 @@
package params
import (
"fmt"
"reflect"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/params/subspace"
)
// Keeper manages global parameter store
// Keeper of the global paramstore
type Keeper struct {
cdc *codec.Codec
key sdk.StoreKey
cdc *codec.Codec
key sdk.StoreKey
tkey sdk.StoreKey
spaces map[string]*Subspace
}
// NewKeeper constructs a new Keeper
func NewKeeper(cdc *codec.Codec, key sdk.StoreKey) Keeper {
return Keeper{
cdc: cdc,
key: key,
}
}
// NewKeeper constructs a params keeper
func NewKeeper(cdc *codec.Codec, key *sdk.KVStoreKey, tkey *sdk.TransientStoreKey) (k Keeper) {
k = Keeper{
cdc: cdc,
key: key,
tkey: tkey,
// InitKeeper constructs a new Keeper with initial parameters
// nolint: errcheck
func InitKeeper(ctx sdk.Context, cdc *codec.Codec, key sdk.StoreKey, params ...interface{}) Keeper {
if len(params)%2 != 0 {
panic("Odd params list length for InitKeeper")
}
k := NewKeeper(cdc, key)
for i := 0; i < len(params); i += 2 {
k.set(ctx, params[i].(string), params[i+1])
spaces: make(map[string]*Subspace),
}
return k
}
// get automatically unmarshalls parameter to pointer
func (k Keeper) get(ctx sdk.Context, key string, ptr interface{}) error {
store := ctx.KVStore(k.key)
bz := store.Get([]byte(key))
return k.cdc.UnmarshalBinary(bz, ptr)
}
// getRaw returns raw byte slice
func (k Keeper) getRaw(ctx sdk.Context, key string) []byte {
store := ctx.KVStore(k.key)
return store.Get([]byte(key))
}
// set automatically marshalls and type check parameter
func (k Keeper) set(ctx sdk.Context, key string, param interface{}) error {
store := ctx.KVStore(k.key)
bz := store.Get([]byte(key))
if bz != nil {
ptrty := reflect.PtrTo(reflect.TypeOf(param))
ptr := reflect.New(ptrty).Interface()
if k.cdc.UnmarshalBinary(bz, ptr) != nil {
return fmt.Errorf("Type mismatch with stored param and provided param")
}
// Allocate subspace used for keepers
func (k Keeper) Subspace(spacename string) Subspace {
_, ok := k.spaces[spacename]
if ok {
panic("subspace already occupied")
}
bz, err := k.cdc.MarshalBinary(param)
if err != nil {
return err
if spacename == "" {
panic("cannot use empty string for subspace")
}
store.Set([]byte(key), bz)
return nil
space := subspace.NewSubspace(k.cdc, k.key, k.tkey, spacename)
k.spaces[spacename] = &space
return space
}
// setRaw sets raw byte slice
func (k Keeper) setRaw(ctx sdk.Context, key string, param []byte) {
store := ctx.KVStore(k.key)
store.Set([]byte(key), param)
}
// Getter returns readonly struct
func (k Keeper) Getter() Getter {
return Getter{k}
}
// Setter returns read/write struct
func (k Keeper) Setter() Setter {
return Setter{Getter{k}}
}
// Getter exposes methods related with only getting params
type Getter struct {
k Keeper
}
// Get exposes get
func (k Getter) Get(ctx sdk.Context, key string, ptr interface{}) error {
return k.k.get(ctx, key, ptr)
}
// GetRaw exposes getRaw
func (k Getter) GetRaw(ctx sdk.Context, key string) []byte {
return k.k.getRaw(ctx, key)
}
// GetString is helper function for string params
func (k Getter) GetString(ctx sdk.Context, key string) (res string, err error) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
err = k.k.cdc.UnmarshalBinary(bz, &res)
return
}
// GetBool is helper function for bool params
func (k Getter) GetBool(ctx sdk.Context, key string) (res bool, err error) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
err = k.k.cdc.UnmarshalBinary(bz, &res)
return
}
// GetInt16 is helper function for int16 params
func (k Getter) GetInt16(ctx sdk.Context, key string) (res int16, err error) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
err = k.k.cdc.UnmarshalBinary(bz, &res)
return
}
// GetInt32 is helper function for int32 params
func (k Getter) GetInt32(ctx sdk.Context, key string) (res int32, err error) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
err = k.k.cdc.UnmarshalBinary(bz, &res)
return
}
// GetInt64 is helper function for int64 params
func (k Getter) GetInt64(ctx sdk.Context, key string) (res int64, err error) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
err = k.k.cdc.UnmarshalBinary(bz, &res)
return
}
// GetUint16 is helper function for uint16 params
func (k Getter) GetUint16(ctx sdk.Context, key string) (res uint16, err error) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
err = k.k.cdc.UnmarshalBinary(bz, &res)
return
}
// GetUint32 is helper function for uint32 params
func (k Getter) GetUint32(ctx sdk.Context, key string) (res uint32, err error) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
err = k.k.cdc.UnmarshalBinary(bz, &res)
return
}
// GetUint64 is helper function for uint64 params
func (k Getter) GetUint64(ctx sdk.Context, key string) (res uint64, err error) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
err = k.k.cdc.UnmarshalBinary(bz, &res)
return
}
// GetInt is helper function for sdk.Int params
func (k Getter) GetInt(ctx sdk.Context, key string) (res sdk.Int, err error) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
err = k.k.cdc.UnmarshalBinary(bz, &res)
return
}
// GetUint is helper function for sdk.Uint params
func (k Getter) GetUint(ctx sdk.Context, key string) (res sdk.Uint, err error) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
err = k.k.cdc.UnmarshalBinary(bz, &res)
return
}
// GetDec is helper function for decimal params
func (k Getter) GetDec(ctx sdk.Context, key string) (res sdk.Dec, err error) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
err = k.k.cdc.UnmarshalBinary(bz, &res)
return
}
// GetStringWithDefault is helper function for string params with default value
func (k Getter) GetStringWithDefault(ctx sdk.Context, key string, def string) (res string) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
if bz == nil {
return def
}
k.k.cdc.MustUnmarshalBinary(bz, &res)
return
}
// GetBoolWithDefault is helper function for bool params with default value
func (k Getter) GetBoolWithDefault(ctx sdk.Context, key string, def bool) (res bool) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
if bz == nil {
return def
}
k.k.cdc.MustUnmarshalBinary(bz, &res)
return
}
// GetInt16WithDefault is helper function for int16 params with default value
func (k Getter) GetInt16WithDefault(ctx sdk.Context, key string, def int16) (res int16) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
if bz == nil {
return def
}
k.k.cdc.MustUnmarshalBinary(bz, &res)
return
}
// GetInt32WithDefault is helper function for int32 params with default value
func (k Getter) GetInt32WithDefault(ctx sdk.Context, key string, def int32) (res int32) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
if bz == nil {
return def
}
k.k.cdc.MustUnmarshalBinary(bz, &res)
return
}
// GetInt64WithDefault is helper function for int64 params with default value
func (k Getter) GetInt64WithDefault(ctx sdk.Context, key string, def int64) (res int64) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
if bz == nil {
return def
}
k.k.cdc.MustUnmarshalBinary(bz, &res)
return
}
// GetUint16WithDefault is helper function for uint16 params with default value
func (k Getter) GetUint16WithDefault(ctx sdk.Context, key string, def uint16) (res uint16) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
if bz == nil {
return def
}
k.k.cdc.MustUnmarshalBinary(bz, &res)
return
}
// GetUint32WithDefault is helper function for uint32 params with default value
func (k Getter) GetUint32WithDefault(ctx sdk.Context, key string, def uint32) (res uint32) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
if bz == nil {
return def
}
k.k.cdc.MustUnmarshalBinary(bz, &res)
return
}
// GetUint64WithDefault is helper function for uint64 params with default value
func (k Getter) GetUint64WithDefault(ctx sdk.Context, key string, def uint64) (res uint64) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
if bz == nil {
return def
}
k.k.cdc.MustUnmarshalBinary(bz, &res)
return
}
// GetIntWithDefault is helper function for sdk.Int params with default value
func (k Getter) GetIntWithDefault(ctx sdk.Context, key string, def sdk.Int) (res sdk.Int) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
if bz == nil {
return def
}
k.k.cdc.MustUnmarshalBinary(bz, &res)
return
}
// GetUintWithDefault is helper function for sdk.Uint params with default value
func (k Getter) GetUintWithDefault(ctx sdk.Context, key string, def sdk.Uint) (res sdk.Uint) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
if bz == nil {
return def
}
k.k.cdc.MustUnmarshalBinary(bz, &res)
return
}
// GetDecWithDefault is helper function for sdk.Dec params with default value
func (k Getter) GetDecWithDefault(ctx sdk.Context, key string, def sdk.Dec) (res sdk.Dec) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
if bz == nil {
return def
}
k.k.cdc.MustUnmarshalBinary(bz, &res)
return
}
// Setter exposes all methods including Set
type Setter struct {
Getter
}
// Set exposes set
func (k Setter) Set(ctx sdk.Context, key string, param interface{}) error {
return k.k.set(ctx, key, param)
}
// SetRaw exposes setRaw
func (k Setter) SetRaw(ctx sdk.Context, key string, param []byte) {
k.k.setRaw(ctx, key, param)
}
// SetString is helper function for string params
func (k Setter) SetString(ctx sdk.Context, key string, param string) {
if err := k.k.set(ctx, key, param); err != nil {
panic(err)
}
}
// SetBool is helper function for bool params
func (k Setter) SetBool(ctx sdk.Context, key string, param bool) {
if err := k.k.set(ctx, key, param); err != nil {
panic(err)
}
}
// SetInt16 is helper function for int16 params
func (k Setter) SetInt16(ctx sdk.Context, key string, param int16) {
if err := k.k.set(ctx, key, param); err != nil {
panic(err)
}
}
// SetInt32 is helper function for int32 params
func (k Setter) SetInt32(ctx sdk.Context, key string, param int32) {
if err := k.k.set(ctx, key, param); err != nil {
panic(err)
}
}
// SetInt64 is helper function for int64 params
func (k Setter) SetInt64(ctx sdk.Context, key string, param int64) {
if err := k.k.set(ctx, key, param); err != nil {
panic(err)
}
}
// SetUint16 is helper function for uint16 params
func (k Setter) SetUint16(ctx sdk.Context, key string, param uint16) {
if err := k.k.set(ctx, key, param); err != nil {
panic(err)
}
}
// SetUint32 is helper function for uint32 params
func (k Setter) SetUint32(ctx sdk.Context, key string, param uint32) {
if err := k.k.set(ctx, key, param); err != nil {
panic(err)
}
}
// SetUint64 is helper function for uint64 params
func (k Setter) SetUint64(ctx sdk.Context, key string, param uint64) {
if err := k.k.set(ctx, key, param); err != nil {
panic(err)
}
}
// SetInt is helper function for sdk.Int params
func (k Setter) SetInt(ctx sdk.Context, key string, param sdk.Int) {
if err := k.k.set(ctx, key, param); err != nil {
panic(err)
}
}
// SetUint is helper function for sdk.Uint params
func (k Setter) SetUint(ctx sdk.Context, key string, param sdk.Uint) {
if err := k.k.set(ctx, key, param); err != nil {
panic(err)
}
}
// SetDec is helper function for decimal params
func (k Setter) SetDec(ctx sdk.Context, key string, param sdk.Dec) {
if err := k.k.set(ctx, key, param); err != nil {
panic(err)
// Get existing substore from keeper
func (k Keeper) GetSubspace(storename string) (Subspace, bool) {
space, ok := k.spaces[storename]
if !ok {
return Subspace{}, false
}
return *space, ok
}

View File

@ -1,9 +1,10 @@
package params
import (
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
dbm "github.com/tendermint/tendermint/libs/db"
@ -14,15 +15,30 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
func defaultContext(key sdk.StoreKey) sdk.Context {
func defaultContext(key sdk.StoreKey, tkey sdk.StoreKey) sdk.Context {
db := dbm.NewMemDB()
cms := store.NewCommitMultiStore(db)
cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db)
cms.MountStoreWithDB(tkey, sdk.StoreTypeTransient, db)
cms.LoadLatestVersion()
ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger())
return ctx
}
type invalid struct{}
type s struct {
I int
}
func createTestCodec() *codec.Codec {
cdc := codec.New()
sdk.RegisterCodec(cdc)
cdc.RegisterConcrete(s{}, "test/s", nil)
cdc.RegisterConcrete(invalid{}, "test/invalid", nil)
return cdc
}
func TestKeeper(t *testing.T) {
kvs := []struct {
key string
@ -33,248 +49,120 @@ func TestKeeper(t *testing.T) {
{"key3", 182},
{"key4", 17582},
{"key5", 2768554},
{"key6", 1157279},
{"key7", 9058701},
}
table := NewTypeTable(
[]byte("key1"), int64(0),
[]byte("key2"), int64(0),
[]byte("key3"), int64(0),
[]byte("key4"), int64(0),
[]byte("key5"), int64(0),
[]byte("key6"), int64(0),
[]byte("key7"), int64(0),
[]byte("extra1"), bool(false),
[]byte("extra2"), string(""),
)
skey := sdk.NewKVStoreKey("test")
ctx := defaultContext(skey)
setter := NewKeeper(codec.New(), skey).Setter()
tkey := sdk.NewTransientStoreKey("transient_test")
ctx := defaultContext(skey, tkey)
store := NewKeeper(codec.New(), skey, tkey).Subspace("test").WithTypeTable(table)
for _, kv := range kvs {
err := setter.Set(ctx, kv.key, kv.param)
assert.Nil(t, err)
for i, kv := range kvs {
require.NotPanics(t, func() { store.Set(ctx, []byte(kv.key), kv.param) }, "store.Set panics, tc #%d", i)
}
for _, kv := range kvs {
for i, kv := range kvs {
var param int64
err := setter.Get(ctx, kv.key, &param)
assert.Nil(t, err)
assert.Equal(t, kv.param, param)
require.NotPanics(t, func() { store.Get(ctx, []byte(kv.key), &param) }, "store.Get panics, tc #%d", i)
require.Equal(t, kv.param, param, "stored param not equal, tc #%d", i)
}
cdc := codec.New()
for _, kv := range kvs {
for i, kv := range kvs {
var param int64
bz := setter.GetRaw(ctx, kv.key)
err := cdc.UnmarshalBinary(bz, &param)
assert.Nil(t, err)
assert.Equal(t, kv.param, param)
bz := store.GetRaw(ctx, []byte(kv.key))
err := cdc.UnmarshalJSON(bz, &param)
require.Nil(t, err, "err is not nil, tc #%d", i)
require.Equal(t, kv.param, param, "stored param not equal, tc #%d", i)
}
for _, kv := range kvs {
for i, kv := range kvs {
var param bool
err := setter.Get(ctx, kv.key, &param)
assert.NotNil(t, err)
require.Panics(t, func() { store.Get(ctx, []byte(kv.key), &param) }, "invalid store.Get not panics, tc #%d", i)
}
for _, kv := range kvs {
err := setter.Set(ctx, kv.key, true)
assert.NotNil(t, err)
for i, kv := range kvs {
require.Panics(t, func() { store.Set(ctx, []byte(kv.key), true) }, "invalid store.Set not panics, tc #%d", i)
}
}
func TestGetter(t *testing.T) {
func TestGet(t *testing.T) {
key := sdk.NewKVStoreKey("test")
ctx := defaultContext(key)
keeper := NewKeeper(codec.New(), key)
g := keeper.Getter()
s := keeper.Setter()
tkey := sdk.NewTransientStoreKey("transient_test")
ctx := defaultContext(key, tkey)
keeper := NewKeeper(createTestCodec(), key, tkey)
kvs := []struct {
key string
param interface{}
zero interface{}
ptr interface{}
}{
{"string", "test"},
{"bool", true},
{"int16", int16(1)},
{"int32", int32(1)},
{"int64", int64(1)},
{"uint16", uint16(1)},
{"uint32", uint32(1)},
{"uint64", uint64(1)},
{"int", sdk.NewInt(1)},
{"uint", sdk.NewUint(1)},
{"rat", sdk.NewDec(1)},
{"string", "test", "", new(string)},
{"bool", true, false, new(bool)},
{"int16", int16(1), int16(0), new(int16)},
{"int32", int32(1), int32(0), new(int32)},
{"int64", int64(1), int64(0), new(int64)},
{"uint16", uint16(1), uint16(0), new(uint16)},
{"uint32", uint32(1), uint32(0), new(uint32)},
{"uint64", uint64(1), uint64(0), new(uint64)},
{"int", sdk.NewInt(1), *new(sdk.Int), new(sdk.Int)},
{"uint", sdk.NewUint(1), *new(sdk.Uint), new(sdk.Uint)},
{"dec", sdk.NewDec(1), *new(sdk.Dec), new(sdk.Dec)},
{"struct", s{1}, s{0}, new(s)},
}
assert.NotPanics(t, func() { s.SetString(ctx, kvs[0].key, "test") })
assert.NotPanics(t, func() { s.SetBool(ctx, kvs[1].key, true) })
assert.NotPanics(t, func() { s.SetInt16(ctx, kvs[2].key, int16(1)) })
assert.NotPanics(t, func() { s.SetInt32(ctx, kvs[3].key, int32(1)) })
assert.NotPanics(t, func() { s.SetInt64(ctx, kvs[4].key, int64(1)) })
assert.NotPanics(t, func() { s.SetUint16(ctx, kvs[5].key, uint16(1)) })
assert.NotPanics(t, func() { s.SetUint32(ctx, kvs[6].key, uint32(1)) })
assert.NotPanics(t, func() { s.SetUint64(ctx, kvs[7].key, uint64(1)) })
assert.NotPanics(t, func() { s.SetInt(ctx, kvs[8].key, sdk.NewInt(1)) })
assert.NotPanics(t, func() { s.SetUint(ctx, kvs[9].key, sdk.NewUint(1)) })
assert.NotPanics(t, func() { s.SetDec(ctx, kvs[10].key, sdk.NewDec(1)) })
table := NewTypeTable(
[]byte("string"), string(""),
[]byte("bool"), bool(false),
[]byte("int16"), int16(0),
[]byte("int32"), int32(0),
[]byte("int64"), int64(0),
[]byte("uint16"), uint16(0),
[]byte("uint32"), uint32(0),
[]byte("uint64"), uint64(0),
[]byte("int"), sdk.Int{},
[]byte("uint"), sdk.Uint{},
[]byte("dec"), sdk.Dec{},
[]byte("struct"), s{},
)
var res interface{}
var err error
store := keeper.Subspace("test").WithTypeTable(table)
// String
def0 := "default"
res, err = g.GetString(ctx, kvs[0].key)
assert.Nil(t, err)
assert.Equal(t, kvs[0].param, res)
for i, kv := range kvs {
require.False(t, store.Modified(ctx, []byte(kv.key)), "store.Modified returns true before setting, tc #%d", i)
require.NotPanics(t, func() { store.Set(ctx, []byte(kv.key), kv.param) }, "store.Set panics, tc #%d", i)
require.True(t, store.Modified(ctx, []byte(kv.key)), "store.Modified returns false after setting, tc #%d", i)
}
_, err = g.GetString(ctx, "invalid")
assert.NotNil(t, err)
for i, kv := range kvs {
require.NotPanics(t, func() { store.GetIfExists(ctx, []byte("invalid"), kv.ptr) }, "store.GetIfExists panics when no value exists, tc #%d", i)
require.Equal(t, kv.zero, reflect.ValueOf(kv.ptr).Elem().Interface(), "store.GetIfExists unmarshalls when no value exists, tc #%d", i)
require.Panics(t, func() { store.Get(ctx, []byte("invalid"), kv.ptr) }, "invalid store.Get not panics when no value exists, tc #%d", i)
require.Equal(t, kv.zero, reflect.ValueOf(kv.ptr).Elem().Interface(), "invalid store.Get unmarshalls when no value exists, tc #%d", i)
res = g.GetStringWithDefault(ctx, kvs[0].key, def0)
assert.Equal(t, kvs[0].param, res)
require.NotPanics(t, func() { store.GetIfExists(ctx, []byte(kv.key), kv.ptr) }, "store.GetIfExists panics, tc #%d", i)
require.Equal(t, kv.param, reflect.ValueOf(kv.ptr).Elem().Interface(), "stored param not equal, tc #%d", i)
require.NotPanics(t, func() { store.Get(ctx, []byte(kv.key), kv.ptr) }, "store.Get panics, tc #%d", i)
require.Equal(t, kv.param, reflect.ValueOf(kv.ptr).Elem().Interface(), "stored param not equal, tc #%d", i)
res = g.GetStringWithDefault(ctx, "invalid", def0)
assert.Equal(t, def0, res)
// Bool
def1 := false
res, err = g.GetBool(ctx, kvs[1].key)
assert.Nil(t, err)
assert.Equal(t, kvs[1].param, res)
_, err = g.GetBool(ctx, "invalid")
assert.NotNil(t, err)
res = g.GetBoolWithDefault(ctx, kvs[1].key, def1)
assert.Equal(t, kvs[1].param, res)
res = g.GetBoolWithDefault(ctx, "invalid", def1)
assert.Equal(t, def1, res)
// Int16
def2 := int16(0)
res, err = g.GetInt16(ctx, kvs[2].key)
assert.Nil(t, err)
assert.Equal(t, kvs[2].param, res)
_, err = g.GetInt16(ctx, "invalid")
assert.NotNil(t, err)
res = g.GetInt16WithDefault(ctx, kvs[2].key, def2)
assert.Equal(t, kvs[2].param, res)
res = g.GetInt16WithDefault(ctx, "invalid", def2)
assert.Equal(t, def2, res)
// Int32
def3 := int32(0)
res, err = g.GetInt32(ctx, kvs[3].key)
assert.Nil(t, err)
assert.Equal(t, kvs[3].param, res)
_, err = g.GetInt32(ctx, "invalid")
assert.NotNil(t, err)
res = g.GetInt32WithDefault(ctx, kvs[3].key, def3)
assert.Equal(t, kvs[3].param, res)
res = g.GetInt32WithDefault(ctx, "invalid", def3)
assert.Equal(t, def3, res)
// Int64
def4 := int64(0)
res, err = g.GetInt64(ctx, kvs[4].key)
assert.Nil(t, err)
assert.Equal(t, kvs[4].param, res)
_, err = g.GetInt64(ctx, "invalid")
assert.NotNil(t, err)
res = g.GetInt64WithDefault(ctx, kvs[4].key, def4)
assert.Equal(t, kvs[4].param, res)
res = g.GetInt64WithDefault(ctx, "invalid", def4)
assert.Equal(t, def4, res)
// Uint16
def5 := uint16(0)
res, err = g.GetUint16(ctx, kvs[5].key)
assert.Nil(t, err)
assert.Equal(t, kvs[5].param, res)
_, err = g.GetUint16(ctx, "invalid")
assert.NotNil(t, err)
res = g.GetUint16WithDefault(ctx, kvs[5].key, def5)
assert.Equal(t, kvs[5].param, res)
res = g.GetUint16WithDefault(ctx, "invalid", def5)
assert.Equal(t, def5, res)
// Uint32
def6 := uint32(0)
res, err = g.GetUint32(ctx, kvs[6].key)
assert.Nil(t, err)
assert.Equal(t, kvs[6].param, res)
_, err = g.GetUint32(ctx, "invalid")
assert.NotNil(t, err)
res = g.GetUint32WithDefault(ctx, kvs[6].key, def6)
assert.Equal(t, kvs[6].param, res)
res = g.GetUint32WithDefault(ctx, "invalid", def6)
assert.Equal(t, def6, res)
// Uint64
def7 := uint64(0)
res, err = g.GetUint64(ctx, kvs[7].key)
assert.Nil(t, err)
assert.Equal(t, kvs[7].param, res)
_, err = g.GetUint64(ctx, "invalid")
assert.NotNil(t, err)
res = g.GetUint64WithDefault(ctx, kvs[7].key, def7)
assert.Equal(t, kvs[7].param, res)
res = g.GetUint64WithDefault(ctx, "invalid", def7)
assert.Equal(t, def7, res)
// Int
def8 := sdk.NewInt(0)
res, err = g.GetInt(ctx, kvs[8].key)
assert.Nil(t, err)
assert.Equal(t, kvs[8].param, res)
_, err = g.GetInt(ctx, "invalid")
assert.NotNil(t, err)
res = g.GetIntWithDefault(ctx, kvs[8].key, def8)
assert.Equal(t, kvs[8].param, res)
res = g.GetIntWithDefault(ctx, "invalid", def8)
assert.Equal(t, def8, res)
// Uint
def9 := sdk.NewUint(0)
res, err = g.GetUint(ctx, kvs[9].key)
assert.Nil(t, err)
assert.Equal(t, kvs[9].param, res)
_, err = g.GetUint(ctx, "invalid")
assert.NotNil(t, err)
res = g.GetUintWithDefault(ctx, kvs[9].key, def9)
assert.Equal(t, kvs[9].param, res)
res = g.GetUintWithDefault(ctx, "invalid", def9)
assert.Equal(t, def9, res)
// Rat
def10 := sdk.NewDec(0)
res, err = g.GetDec(ctx, kvs[10].key)
assert.Nil(t, err)
assert.Equal(t, kvs[10].param, res)
_, err = g.GetDec(ctx, "invalid")
assert.NotNil(t, err)
res = g.GetDecWithDefault(ctx, kvs[10].key, def10)
assert.Equal(t, kvs[10].param, res)
res = g.GetDecWithDefault(ctx, "invalid", def10)
assert.Equal(t, def10, res)
require.Panics(t, func() { store.Get(ctx, []byte("invalid"), kv.ptr) }, "invalid store.Get not panics when no value exists, tc #%d", i)
require.Equal(t, kv.param, reflect.ValueOf(kv.ptr).Elem().Interface(), "invalid store.Get unmarshalls when no value existt, tc #%d", i)
require.Panics(t, func() { store.Get(ctx, []byte(kv.key), nil) }, "invalid store.Get not panics when the pointer is nil, tc #%d", i)
require.Panics(t, func() { store.Get(ctx, []byte(kv.key), new(invalid)) }, "invalid store.Get not panics when the pointer is different type, tc #%d", i)
}
}

View File

@ -1,37 +0,0 @@
package params
import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// GenesisState defines initial activated msg types
type GenesisState struct {
ActivatedTypes []string `json:"activated-types"`
}
// ActivatedParamKey - paramstore key for msg type activation
func ActivatedParamKey(ty string) string {
return "Activated/" + ty
}
// 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)
}
}
// NewAnteHandler returns an AnteHandler that checks
// whether msg type is activate or not
func NewAnteHandler(k Keeper) sdk.AnteHandler {
return func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, sdk.Result, bool) {
for _, msg := range tx.GetMsgs() {
ok := k.Getter().GetBoolWithDefault(ctx, ActivatedParamKey(msg.Type()), false)
if !ok {
return ctx, sdk.ErrUnauthorized("deactivated msg type").Result(), true
}
}
return ctx, sdk.Result{}, false
}
}

19
x/params/subspace.go Normal file
View File

@ -0,0 +1,19 @@
package params
import (
"github.com/cosmos/cosmos-sdk/x/params/subspace"
)
// re-export types from subspace
type (
Subspace = subspace.Subspace
ReadOnlySubspace = subspace.ReadOnlySubspace
ParamSet = subspace.ParamSet
KeyValuePairs = subspace.KeyValuePairs
TypeTable = subspace.TypeTable
)
// re-export functions from subspace
func NewTypeTable(keytypes ...interface{}) TypeTable {
return subspace.NewTypeTable(keytypes...)
}

14
x/params/subspace/doc.go Normal file
View File

@ -0,0 +1,14 @@
package subspace
/*
To prevent namespace collision between consumer modules, we define type
"space". A Space can only be generated by the keeper, and the keeper checks
the existence of the space having the same name before generating the
space.
Consumer modules must take a space (via Keeper.Subspace), not the keeper
itself. This isolates each modules from the others and make them modify the
parameters safely. Keeper can be treated as master permission for all
subspaces (via Keeper.GetSubspace), so should be passed to proper modules
(ex. gov)
*/

15
x/params/subspace/pair.go Normal file
View File

@ -0,0 +1,15 @@
package subspace
// Used for associating paramsubspace key and field of param structs
type KeyValuePair struct {
Key []byte
Value interface{}
}
// Slice of KeyFieldPair
type KeyValuePairs []KeyValuePair
// Interface for structs containing parameters for a module
type ParamSet interface {
KeyValuePairs() KeyValuePairs
}

View File

@ -0,0 +1,198 @@
package subspace
import (
"reflect"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Additional capicity to be allocated for Subspace.name
// So we don't have to allocate extra space each time appending to the key
const extraKeyCap = 20
// Individual parameter store for each keeper
// Transient store persists for a block, so we use it for
// recording whether the parameter has been changed or not
type Subspace struct {
cdc *codec.Codec
key sdk.StoreKey // []byte -> []byte, stores parameter
tkey sdk.StoreKey // []byte -> bool, stores parameter change
name []byte
table TypeTable
}
// NewSubspace constructs a store with namestore
func NewSubspace(cdc *codec.Codec, key sdk.StoreKey, tkey sdk.StoreKey, name string) (res Subspace) {
res = Subspace{
cdc: cdc,
key: key,
tkey: tkey,
}
namebz := []byte(name)
res.name = make([]byte, len(namebz), len(namebz)+extraKeyCap)
copy(res.name, namebz)
return
}
// WithTypeTable initializes TypeTable and returns modified Subspace
func (s Subspace) WithTypeTable(table TypeTable) (res Subspace) {
if table == nil {
panic("SetTypeTable() called with nil TypeTable")
}
if s.table != nil {
panic("SetTypeTable() called on initialized Subspace")
}
res = Subspace{
cdc: s.cdc,
key: s.key,
tkey: s.tkey,
name: s.name,
table: table,
}
return
}
// Returns a KVStore identical with ctx.KVStore(s.key).Prefix()
func (s Subspace) kvStore(ctx sdk.Context) sdk.KVStore {
// append here is safe, appends within a function won't cause
// weird side effects when its singlethreaded
return ctx.KVStore(s.key).Prefix(append(s.name, '/'))
}
// Returns a KVStore identical with ctx.TransientStore(s.tkey).Prefix()
func (s Subspace) transientStore(ctx sdk.Context) sdk.KVStore {
// append here is safe, appends within a function won't cause
// weird side effects when its singlethreaded
return ctx.TransientStore(s.tkey).Prefix(append(s.name, '/'))
}
// Get parameter from store
func (s Subspace) Get(ctx sdk.Context, key []byte, ptr interface{}) {
store := s.kvStore(ctx)
bz := store.Get(key)
err := s.cdc.UnmarshalJSON(bz, ptr)
if err != nil {
panic(err)
}
}
// GetIfExists do not modify ptr if the stored parameter is nil
func (s Subspace) GetIfExists(ctx sdk.Context, key []byte, ptr interface{}) {
store := s.kvStore(ctx)
bz := store.Get(key)
if bz == nil {
return
}
err := s.cdc.UnmarshalJSON(bz, ptr)
if err != nil {
panic(err)
}
}
// Get raw bytes of parameter from store
func (s Subspace) GetRaw(ctx sdk.Context, key []byte) []byte {
store := s.kvStore(ctx)
return store.Get(key)
}
// Check if the parameter is set in the store
func (s Subspace) Has(ctx sdk.Context, key []byte) bool {
store := s.kvStore(ctx)
return store.Has(key)
}
// Returns true if the parameter is set in the block
func (s Subspace) Modified(ctx sdk.Context, key []byte) bool {
tstore := s.transientStore(ctx)
return tstore.Has(key)
}
// Set parameter, return error if stored parameter has different type from input
// Also set to the transient store to record change
func (s Subspace) Set(ctx sdk.Context, key []byte, param interface{}) {
store := s.kvStore(ctx)
ty, ok := s.table[string(key)]
if !ok {
panic("Parameter not registered")
}
pty := reflect.TypeOf(param)
if pty.Kind() == reflect.Ptr {
pty = pty.Elem()
}
if pty != ty {
panic("Type mismatch with registered table")
}
bz, err := s.cdc.MarshalJSON(param)
if err != nil {
panic(err)
}
store.Set(key, bz)
tstore := s.transientStore(ctx)
tstore.Set(key, []byte{})
}
// Get to ParamSet
func (s Subspace) GetParamSet(ctx sdk.Context, ps ParamSet) {
for _, pair := range ps.KeyValuePairs() {
s.Get(ctx, pair.Key, pair.Value)
}
}
// Set from ParamSet
func (s Subspace) SetParamSet(ctx sdk.Context, ps ParamSet) {
for _, pair := range ps.KeyValuePairs() {
// pair.Field is a pointer to the field, so indirecting the ptr.
// go-amino automatically handles it but just for sure,
// since SetStruct is meant to be used in InitGenesis
// so this method will not be called frequently
v := reflect.Indirect(reflect.ValueOf(pair.Value)).Interface()
s.Set(ctx, pair.Key, v)
}
}
// Returns name of Subspace
func (s Subspace) Name() string {
return string(s.name)
}
// Wrapper of Subspace, provides immutable functions only
type ReadOnlySubspace struct {
s Subspace
}
// Exposes Get
func (ros ReadOnlySubspace) Get(ctx sdk.Context, key []byte, ptr interface{}) {
ros.s.Get(ctx, key, ptr)
}
// Exposes GetRaw
func (ros ReadOnlySubspace) GetRaw(ctx sdk.Context, key []byte) []byte {
return ros.s.GetRaw(ctx, key)
}
// Exposes Has
func (ros ReadOnlySubspace) Has(ctx sdk.Context, key []byte) bool {
return ros.s.Has(ctx, key)
}
// Exposes Modified
func (ros ReadOnlySubspace) Modified(ctx sdk.Context, key []byte) bool {
return ros.s.Modified(ctx, key)
}
// Exposes Space
func (ros ReadOnlySubspace) Name() string {
return ros.s.Name()
}

View File

@ -0,0 +1,50 @@
package subspace
import (
"reflect"
)
// TypeTable subspaces appropriate type for each parameter key
type TypeTable map[string]reflect.Type
// Constructs new table
func NewTypeTable(keytypes ...interface{}) (res TypeTable) {
if len(keytypes)%2 != 0 {
panic("odd number arguments in NewTypeTypeTable")
}
res = make(map[string]reflect.Type)
for i := 0; i < len(keytypes); i += 2 {
res = res.RegisterType(keytypes[i].([]byte), keytypes[i+1])
}
return
}
// Register single key-type pair
func (t TypeTable) RegisterType(key []byte, ty interface{}) TypeTable {
keystr := string(key)
if _, ok := t[keystr]; ok {
panic("duplicate parameter key")
}
rty := reflect.TypeOf(ty)
// Indirect rty if it is ptr
if rty.Kind() == reflect.Ptr {
rty = rty.Elem()
}
t[keystr] = rty
return t
}
// Register multiple pairs from ParamSet
func (t TypeTable) RegisterParamSet(ps ParamSet) TypeTable {
for _, kvp := range ps.KeyValuePairs() {
t = t.RegisterType(kvp.Key, kvp.Value)
}
return t
}

View File

@ -0,0 +1,40 @@
package subspace
import (
"os"
"testing"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Keys for parameter access
const (
TestParamStore = "ParamsTest"
)
// Returns components for testing
func DefaultTestComponents(t *testing.T, table TypeTable) (sdk.Context, Subspace, func() sdk.CommitID) {
cdc := codec.New()
key := sdk.NewKVStoreKey("params")
tkey := sdk.NewTransientStoreKey("tparams")
db := dbm.NewMemDB()
ms := store.NewCommitMultiStore(db)
ms.WithTracer(os.Stdout)
ms.WithTracingContext(sdk.TraceContext{})
ms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db)
ms.MountStoreWithDB(tkey, sdk.StoreTypeTransient, db)
err := ms.LoadLatestVersion()
require.Nil(t, err)
ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewTMLogger(os.Stdout))
subspace := NewSubspace(cdc, key, tkey, TestParamStore).WithTypeTable(table)
return ctx, subspace, ms.Commit
}

View File

@ -28,18 +28,21 @@ func getMockApp(t *testing.T) (*mock.App, stake.Keeper, Keeper) {
keyStake := sdk.NewKVStoreKey("stake")
tkeyStake := sdk.NewTransientStoreKey("transient_stake")
keySlashing := sdk.NewKVStoreKey("slashing")
keyParams := sdk.NewKVStoreKey("params")
bankKeeper := bank.NewBaseKeeper(mapp.AccountMapper)
paramsKeeper := params.NewKeeper(mapp.Cdc, keyParams)
stakeKeeper := stake.NewKeeper(mapp.Cdc, keyStake, tkeyStake, bankKeeper, mapp.RegisterCodespace(stake.DefaultCodespace))
keeper := NewKeeper(mapp.Cdc, keySlashing, stakeKeeper, paramsKeeper.Getter(), mapp.RegisterCodespace(DefaultCodespace))
keyParams := sdk.NewKVStoreKey("params")
tkeyParams := sdk.NewTransientStoreKey("transient_params")
bankKeeper := bank.NewBaseKeeper(mapp.AccountMapper)
paramsKeeper := params.NewKeeper(mapp.Cdc, keyParams, tkeyParams)
stakeKeeper := stake.NewKeeper(mapp.Cdc, keyStake, tkeyStake, bankKeeper, paramsKeeper.Subspace(stake.DefaultParamspace), mapp.RegisterCodespace(stake.DefaultCodespace))
keeper := NewKeeper(mapp.Cdc, keySlashing, stakeKeeper, paramsKeeper.Subspace(DefaultParamspace), mapp.RegisterCodespace(DefaultCodespace))
mapp.Router().AddRoute("stake", stake.NewHandler(stakeKeeper))
mapp.Router().AddRoute("slashing", NewHandler(keeper))
mapp.SetEndBlocker(getEndBlocker(stakeKeeper))
mapp.SetInitChainer(getInitChainer(mapp, stakeKeeper))
require.NoError(t, mapp.CompleteSetup(keyStake, keySlashing, keyParams, tkeyStake))
require.NoError(t, mapp.CompleteSetup(keyStake, tkeyStake, keySlashing, keyParams, tkeyParams))
return mapp, stakeKeeper, keeper
}

View File

@ -5,10 +5,24 @@ import (
"github.com/cosmos/cosmos-sdk/x/stake/types"
)
// InitGenesis initializes the keeper's address to pubkey map.
func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) {
for _, validator := range data.Validators {
// GenesisState - all slashing state that must be provided at genesis
type GenesisState struct {
Params Params
}
// HubDefaultGenesisState - default GenesisState used by Cosmos Hub
func DefaultGenesisState() GenesisState {
return GenesisState{
Params: DefaultParams(),
}
}
// InitGenesis initialize default parameters
// and the keeper's address to pubkey map
func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState, sdata types.GenesisState) {
for _, validator := range sdata.Validators {
keeper.addPubkey(ctx, validator.GetConsPubKey())
}
return
keeper.paramspace.SetParamSet(ctx, &data.Params)
}

View File

@ -12,7 +12,7 @@ import (
func TestCannotUnjailUnlessJailed(t *testing.T) {
// initial setup
ctx, ck, sk, _, keeper := createTestInput(t)
ctx, ck, sk, _, keeper := createTestInput(t, DefaultParams())
slh := NewHandler(keeper)
amtInt := int64(100)
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
@ -30,7 +30,7 @@ func TestCannotUnjailUnlessJailed(t *testing.T) {
}
func TestJailedValidatorDelegations(t *testing.T) {
ctx, _, stakeKeeper, _, slashingKeeper := createTestInput(t)
ctx, _, stakeKeeper, _, slashingKeeper := createTestInput(t, DefaultParams())
stakeParams := stakeKeeper.GetParams(ctx)
stakeParams.UnbondingTime = 0

View File

@ -9,7 +9,7 @@ import (
)
func TestHookOnValidatorBonded(t *testing.T) {
ctx, _, _, _, keeper := createTestInput(t)
ctx, _, _, _, keeper := createTestInput(t, DefaultParams())
addr := sdk.ConsAddress(addrs[0])
keeper.onValidatorBonded(ctx, addr)
period := keeper.getValidatorSlashingPeriodForHeight(ctx, addr, ctx.BlockHeight())
@ -17,7 +17,7 @@ func TestHookOnValidatorBonded(t *testing.T) {
}
func TestHookOnValidatorBeginUnbonding(t *testing.T) {
ctx, _, _, _, keeper := createTestInput(t)
ctx, _, _, _, keeper := createTestInput(t, DefaultParams())
addr := sdk.ConsAddress(addrs[0])
keeper.onValidatorBonded(ctx, addr)
keeper.onValidatorBeginUnbonding(ctx, addr)

View File

@ -19,18 +19,19 @@ type Keeper struct {
storeKey sdk.StoreKey
cdc *codec.Codec
validatorSet sdk.ValidatorSet
params params.Getter
paramspace params.Subspace
// codespace
codespace sdk.CodespaceType
}
// NewKeeper creates a slashing keeper
func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, vs sdk.ValidatorSet, params params.Getter, codespace sdk.CodespaceType) Keeper {
func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, vs sdk.ValidatorSet, paramspace params.Subspace, codespace sdk.CodespaceType) Keeper {
keeper := Keeper{
storeKey: key,
cdc: cdc,
validatorSet: vs,
params: params,
paramspace: paramspace.WithTypeTable(ParamTypeTable()),
codespace: codespace,
}
return keeper

View File

@ -12,10 +12,12 @@ import (
// Have to change these parameters for tests
// lest the tests take forever
func init() {
defaultSignedBlocksWindow = 1000
defaultDowntimeUnbondDuration = 60 * 60
defaultDoubleSignUnbondDuration = 60 * 60
func keeperTestParams() Params {
params := DefaultParams()
params.SignedBlocksWindow = 1000
params.DowntimeUnbondDuration = 60 * 60
params.DoubleSignUnbondDuration = 60 * 60
return params
}
// ______________________________________________________________
@ -25,7 +27,7 @@ func init() {
func TestHandleDoubleSign(t *testing.T) {
// initial setup
ctx, ck, sk, _, keeper := createTestInput(t)
ctx, ck, sk, _, keeper := createTestInput(t, keeperTestParams())
// validator added pre-genesis
ctx = ctx.WithBlockHeight(-1)
sk = sk.WithHooks(keeper.Hooks())
@ -68,7 +70,7 @@ func TestHandleDoubleSign(t *testing.T) {
func TestSlashingPeriodCap(t *testing.T) {
// initial setup
ctx, ck, sk, _, keeper := createTestInput(t)
ctx, ck, sk, _, keeper := createTestInput(t, DefaultParams())
sk = sk.WithHooks(keeper.Hooks())
amtInt := int64(100)
operatorAddr, amt := addrs[0], sdk.NewInt(amtInt)
@ -134,7 +136,7 @@ func TestSlashingPeriodCap(t *testing.T) {
func TestHandleAbsentValidator(t *testing.T) {
// initial setup
ctx, ck, sk, _, keeper := createTestInput(t)
ctx, ck, sk, _, keeper := createTestInput(t, keeperTestParams())
sk = sk.WithHooks(keeper.Hooks())
amtInt := int64(100)
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
@ -289,7 +291,7 @@ func TestHandleAbsentValidator(t *testing.T) {
// and that they are not immediately jailed
func TestHandleNewValidator(t *testing.T) {
// initial setup
ctx, ck, sk, _, keeper := createTestInput(t)
ctx, ck, sk, _, keeper := createTestInput(t, keeperTestParams())
addr, val, amt := addrs[0], pks[0], int64(100)
sh := stake.NewHandler(sk)
got := sh(ctx, NewTestMsgCreateValidator(addr, val, sdk.NewInt(amt)))
@ -326,7 +328,7 @@ func TestHandleNewValidator(t *testing.T) {
func TestHandleAlreadyJailed(t *testing.T) {
// initial setup
ctx, _, sk, _, keeper := createTestInput(t)
ctx, _, sk, _, keeper := createTestInput(t, DefaultParams())
amtInt := int64(100)
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
sh := stake.NewHandler(sk)

View File

@ -4,77 +4,119 @@ import (
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/params"
)
// nolint
// Default parameter namespace
const (
MaxEvidenceAgeKey = "slashing/MaxEvidenceAge"
SignedBlocksWindowKey = "slashing/SignedBlocksWindow"
MinSignedPerWindowKey = "slashing/MinSignedPerWindow"
DoubleSignUnbondDurationKey = "slashing/DoubleSignUnbondDuration"
DowntimeUnbondDurationKey = "slashing/DowntimeUnbondDuration"
SlashFractionDoubleSignKey = "slashing/SlashFractionDoubleSign"
SlashFractionDowntimeKey = "slashing/SlashFractionDowntime"
DefaultParamspace = "slashing"
)
// Parameter store key
var (
KeyMaxEvidenceAge = []byte("MaxEvidenceAge")
KeySignedBlocksWindow = []byte("SignedBlocksWindow")
KeyMinSignedPerWindow = []byte("MinSignedPerWindow")
KeyDoubleSignUnbondDuration = []byte("DoubleSignUnbondDuration")
KeyDowntimeUnbondDuration = []byte("DowntimeUnbondDuration")
KeySlashFractionDoubleSign = []byte("SlashFractionDoubleSign")
KeySlashFractionDowntime = []byte("SlashFractionDowntime")
)
// ParamTypeTable for slashing module
func ParamTypeTable() params.TypeTable {
return params.NewTypeTable().RegisterParamSet(&Params{})
}
// Params - used for initializing default parameter for slashing at genesis
type Params struct {
MaxEvidenceAge time.Duration `json:"max-evidence-age"`
SignedBlocksWindow int64 `json:"signed-blocks-window"`
MinSignedPerWindow sdk.Dec `json:"min-signed-per-window"`
DoubleSignUnbondDuration time.Duration `json:"double-sign-unbond-duration"`
DowntimeUnbondDuration time.Duration `json:"downtime-unbond-duration"`
SlashFractionDoubleSign sdk.Dec `json:"slash-fraction-double-sign"`
SlashFractionDowntime sdk.Dec `json:"slash-fraction-downtime"`
}
// Implements params.ParamStruct
func (p *Params) KeyValuePairs() params.KeyValuePairs {
return params.KeyValuePairs{
{KeyMaxEvidenceAge, &p.MaxEvidenceAge},
{KeySignedBlocksWindow, &p.SignedBlocksWindow},
{KeyMinSignedPerWindow, &p.MinSignedPerWindow},
{KeyDoubleSignUnbondDuration, &p.DoubleSignUnbondDuration},
{KeyDowntimeUnbondDuration, &p.DowntimeUnbondDuration},
{KeySlashFractionDoubleSign, &p.SlashFractionDoubleSign},
{KeySlashFractionDowntime, &p.SlashFractionDowntime},
}
}
// Default parameters used by Cosmos Hub
func DefaultParams() Params {
return Params{
// defaultMaxEvidenceAge = 60 * 60 * 24 * 7 * 3
// TODO Temporarily set to 2 minutes for testnets.
MaxEvidenceAge: 60 * 2 * time.Second,
// TODO Temporarily set to five minutes for testnets
DoubleSignUnbondDuration: 60 * 5 * time.Second,
// TODO Temporarily set to 100 blocks for testnets
SignedBlocksWindow: 100,
// TODO Temporarily set to 10 minutes for testnets
DowntimeUnbondDuration: 60 * 10 * time.Second,
MinSignedPerWindow: sdk.NewDecWithPrec(5, 1),
SlashFractionDoubleSign: sdk.NewDec(1).Quo(sdk.NewDec(20)),
SlashFractionDowntime: sdk.NewDec(1).Quo(sdk.NewDec(100)),
}
}
// MaxEvidenceAge - Max age for evidence - 21 days (3 weeks)
// MaxEvidenceAge = 60 * 60 * 24 * 7 * 3
func (k Keeper) MaxEvidenceAge(ctx sdk.Context) time.Duration {
return time.Duration(k.params.GetInt64WithDefault(ctx, MaxEvidenceAgeKey, defaultMaxEvidenceAge)) * time.Second
func (k Keeper) MaxEvidenceAge(ctx sdk.Context) (res time.Duration) {
k.paramspace.Get(ctx, KeyMaxEvidenceAge, &res)
return
}
// SignedBlocksWindow - sliding window for downtime slashing
func (k Keeper) SignedBlocksWindow(ctx sdk.Context) int64 {
return k.params.GetInt64WithDefault(ctx, SignedBlocksWindowKey, defaultSignedBlocksWindow)
func (k Keeper) SignedBlocksWindow(ctx sdk.Context) (res int64) {
k.paramspace.Get(ctx, KeySignedBlocksWindow, &res)
return
}
// Downtime slashing thershold - default 50%
// Downtime slashing thershold - default 50% of the SignedBlocksWindow
func (k Keeper) MinSignedPerWindow(ctx sdk.Context) int64 {
minSignedPerWindow := k.params.GetDecWithDefault(ctx, MinSignedPerWindowKey, defaultMinSignedPerWindow)
var minSignedPerWindow sdk.Dec
k.paramspace.Get(ctx, KeyMinSignedPerWindow, &minSignedPerWindow)
signedBlocksWindow := k.SignedBlocksWindow(ctx)
return sdk.NewDec(signedBlocksWindow).Mul(minSignedPerWindow).RoundInt64()
}
// Double-sign unbond duration
func (k Keeper) DoubleSignUnbondDuration(ctx sdk.Context) time.Duration {
return time.Duration(k.params.GetInt64WithDefault(ctx, DoubleSignUnbondDurationKey, defaultDoubleSignUnbondDuration)) * time.Second
func (k Keeper) DoubleSignUnbondDuration(ctx sdk.Context) (res time.Duration) {
k.paramspace.Get(ctx, KeyDoubleSignUnbondDuration, &res)
return
}
// Downtime unbond duration
func (k Keeper) DowntimeUnbondDuration(ctx sdk.Context) time.Duration {
return time.Duration(k.params.GetInt64WithDefault(ctx, DowntimeUnbondDurationKey, defaultDowntimeUnbondDuration)) * time.Second
func (k Keeper) DowntimeUnbondDuration(ctx sdk.Context) (res time.Duration) {
k.paramspace.Get(ctx, KeyDowntimeUnbondDuration, &res)
return
}
// SlashFractionDoubleSign - currently default 5%
func (k Keeper) SlashFractionDoubleSign(ctx sdk.Context) sdk.Dec {
return k.params.GetDecWithDefault(ctx, SlashFractionDoubleSignKey, defaultSlashFractionDoubleSign)
func (k Keeper) SlashFractionDoubleSign(ctx sdk.Context) (res sdk.Dec) {
k.paramspace.Get(ctx, KeySlashFractionDoubleSign, &res)
return
}
// SlashFractionDowntime - currently default 1%
func (k Keeper) SlashFractionDowntime(ctx sdk.Context) sdk.Dec {
return k.params.GetDecWithDefault(ctx, SlashFractionDowntimeKey, defaultSlashFractionDowntime)
func (k Keeper) SlashFractionDowntime(ctx sdk.Context) (res sdk.Dec) {
k.paramspace.Get(ctx, KeySlashFractionDowntime, &res)
return
}
// declared as var because of keeper_test.go
// TODO: make it const or parameter of NewKeeper
var (
// defaultMaxEvidenceAge = 60 * 60 * 24 * 7 * 3
// TODO Temporarily set to 2 minutes for testnets.
defaultMaxEvidenceAge int64 = 60 * 2
// TODO Temporarily set to five minutes for testnets
defaultDoubleSignUnbondDuration int64 = 60 * 5
// TODO Temporarily set to 10000 blocks for testnets
defaultSignedBlocksWindow int64 = 10000
// TODO Temporarily set to 10 minutes for testnets
defaultDowntimeUnbondDuration int64 = 60 * 10
defaultMinSignedPerWindow = sdk.NewDecWithPrec(5, 1)
defaultSlashFractionDoubleSign = sdk.NewDec(1).Quo(sdk.NewDec(20))
defaultSlashFractionDowntime = sdk.NewDec(1).Quo(sdk.NewDec(100))
)

View File

@ -10,7 +10,7 @@ import (
)
func TestGetSetValidatorSigningInfo(t *testing.T) {
ctx, _, _, _, keeper := createTestInput(t)
ctx, _, _, _, keeper := createTestInput(t, DefaultParams())
info, found := keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(addrs[0]))
require.False(t, found)
newInfo := ValidatorSigningInfo{
@ -29,7 +29,7 @@ func TestGetSetValidatorSigningInfo(t *testing.T) {
}
func TestGetSetValidatorSigningBitArray(t *testing.T) {
ctx, _, _, _, keeper := createTestInput(t)
ctx, _, _, _, keeper := createTestInput(t, DefaultParams())
signed := keeper.getValidatorSigningBitArray(ctx, sdk.ConsAddress(addrs[0]), 0)
require.False(t, signed) // treat empty key as unsigned
keeper.setValidatorSigningBitArray(ctx, sdk.ConsAddress(addrs[0]), 0, true)

View File

@ -9,7 +9,7 @@ import (
)
func TestGetSetValidatorSlashingPeriod(t *testing.T) {
ctx, _, _, _, keeper := createTestInput(t)
ctx, _, _, _, keeper := createTestInput(t, DefaultParams())
addr := sdk.ConsAddress(addrs[0])
height := int64(5)
require.Panics(t, func() { keeper.getValidatorSlashingPeriodForHeight(ctx, addr, height) })
@ -60,7 +60,7 @@ func TestGetSetValidatorSlashingPeriod(t *testing.T) {
}
func TestValidatorSlashingPeriodCap(t *testing.T) {
ctx, _, _, _, keeper := createTestInput(t)
ctx, _, _, _, keeper := createTestInput(t, DefaultParams())
addr := sdk.ConsAddress(addrs[0])
height := int64(5)
newPeriod := ValidatorSlashingPeriod{

View File

@ -49,12 +49,13 @@ func createTestCodec() *codec.Codec {
return cdc
}
func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, params.Setter, Keeper) {
func createTestInput(t *testing.T, defaults Params) (sdk.Context, bank.Keeper, stake.Keeper, params.Subspace, Keeper) {
keyAcc := sdk.NewKVStoreKey("acc")
keyStake := sdk.NewKVStoreKey("stake")
tkeyStake := sdk.NewTransientStoreKey("transient_stake")
keySlashing := sdk.NewKVStoreKey("slashing")
keyParams := sdk.NewKVStoreKey("params")
tkeyParams := sdk.NewTransientStoreKey("transient_params")
db := dbm.NewMemDB()
ms := store.NewCommitMultiStore(db)
ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db)
@ -62,14 +63,16 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, para
ms.MountStoreWithDB(keyStake, sdk.StoreTypeIAVL, db)
ms.MountStoreWithDB(keySlashing, sdk.StoreTypeIAVL, db)
ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db)
ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db)
err := ms.LoadLatestVersion()
require.Nil(t, err)
ctx := sdk.NewContext(ms, abci.Header{Time: time.Unix(0, 0)}, false, log.NewTMLogger(os.Stdout))
cdc := createTestCodec()
accountMapper := auth.NewAccountMapper(cdc, keyAcc, auth.ProtoBaseAccount)
ck := bank.NewBaseKeeper(accountMapper)
params := params.NewKeeper(cdc, keyParams)
sk := stake.NewKeeper(cdc, keyStake, tkeyStake, ck, stake.DefaultCodespace)
paramsKeeper := params.NewKeeper(cdc, keyParams, tkeyParams)
sk := stake.NewKeeper(cdc, keyStake, tkeyStake, ck, paramsKeeper.Subspace(stake.DefaultParamspace), stake.DefaultCodespace)
genesis := stake.DefaultGenesisState()
genesis.Pool.LooseTokens = sdk.NewDec(initCoins.MulRaw(int64(len(addrs))).Int64())
@ -83,8 +86,14 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, para
})
}
require.Nil(t, err)
keeper := NewKeeper(cdc, keySlashing, sk, params.Getter(), DefaultCodespace)
return ctx, ck, sk, params.Setter(), keeper
paramstore := paramsKeeper.Subspace(DefaultParamspace)
keeper := NewKeeper(cdc, keySlashing, sk, paramstore, DefaultCodespace)
require.NotPanics(t, func() {
InitGenesis(ctx, keeper, GenesisState{defaults}, genesis)
})
return ctx, ck, sk, paramstore, keeper
}
func newPubKey(pk string) (res crypto.PubKey) {

View File

@ -13,7 +13,7 @@ import (
)
func TestBeginBlocker(t *testing.T) {
ctx, ck, sk, _, keeper := createTestInput(t)
ctx, ck, sk, _, keeper := createTestInput(t, DefaultParams())
addr, pk, amt := addrs[2], pks[2], sdk.NewInt(100)
// bond the validator

View File

@ -7,6 +7,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/mock"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
)
@ -18,15 +19,21 @@ func getMockApp(t *testing.T) (*mock.App, Keeper) {
RegisterCodec(mApp.Cdc)
keyStake := sdk.NewKVStoreKey("stake")
tkeyStake := sdk.NewTransientStoreKey("transient_stake")
keyParams := sdk.NewKVStoreKey("params")
tkeyParams := sdk.NewTransientStoreKey("transient_params")
bankKeeper := bank.NewBaseKeeper(mApp.AccountMapper)
keeper := NewKeeper(mApp.Cdc, keyStake, tkeyStake, bankKeeper, mApp.RegisterCodespace(DefaultCodespace))
pk := params.NewKeeper(mApp.Cdc, keyParams, tkeyParams)
keeper := NewKeeper(mApp.Cdc, keyStake, tkeyStake, bankKeeper, pk.Subspace(DefaultParamspace), mApp.RegisterCodespace(DefaultCodespace))
mApp.Router().AddRoute("stake", NewHandler(keeper))
mApp.SetEndBlocker(getEndBlocker(keeper))
mApp.SetInitChainer(getInitChainer(mApp, keeper))
require.NoError(t, mApp.CompleteSetup(keyStake, tkeyStake))
require.NoError(t, mApp.CompleteSetup(keyStake, tkeyStake, keyParams, tkeyParams))
return mApp, keeper
}

View File

@ -464,15 +464,17 @@ func GetCmdQueryParams(storeName string, cdc *codec.Codec) *cobra.Command {
Short: "Query the current staking parameters information",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
key := stake.ParamKey
cliCtx := context.NewCLIContext().WithCodec(cdc)
res, err := cliCtx.QueryStore(key, storeName)
bz, err := cliCtx.QueryWithData("custom/stake/"+stake.QueryParameters, nil)
if err != nil {
return err
}
params := types.MustUnmarshalParams(cdc, res)
var params stake.Params
err = cdc.UnmarshalJSON(bz, &params)
if err != nil {
return err
}
switch viper.Get(cli.OutputFlag) {
case "text":

View File

@ -35,6 +35,8 @@ func NewHandler(k keeper.Keeper) sdk.Handler {
func EndBlocker(ctx sdk.Context, k keeper.Keeper) (ValidatorUpdates []abci.ValidatorUpdate) {
endBlockerTags := sdk.EmptyTags()
k.UnbondAllMatureValidatorQueue(ctx)
matureUnbonds := k.DequeueAllMatureUnbondingQueue(ctx, ctx.BlockHeader().Time)
for _, dvPair := range matureUnbonds {
err := k.CompleteUnbonding(ctx, dvPair.DelegatorAddr, dvPair.ValidatorAddr)

View File

@ -602,6 +602,56 @@ func TestJailValidator(t *testing.T) {
require.True(t, got.IsOK(), "expected ok, got %v", got)
}
func TestValidatorQueue(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1]
// set the unbonding time
params := keeper.GetParams(ctx)
params.UnbondingTime = 7 * time.Second
keeper.SetParams(ctx, params)
// create the validator
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], 10)
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
// bond a delegator
msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, 10)
got = handleMsgDelegate(ctx, msgDelegate, keeper)
require.True(t, got.IsOK(), "expected ok, got %v", got)
EndBlocker(ctx, keeper)
// unbond the all self-delegation to put validator in unbonding state
msgBeginUnbondingValidator := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr), validatorAddr, sdk.NewDec(10))
got = handleMsgBeginUnbonding(ctx, msgBeginUnbondingValidator, keeper)
require.True(t, got.IsOK(), "expected no error: %v", got)
var finishTime time.Time
types.MsgCdc.MustUnmarshalBinary(got.Data, &finishTime)
ctx = ctx.WithBlockTime(finishTime)
EndBlocker(ctx, keeper)
origHeader := ctx.BlockHeader()
validator, found := keeper.GetValidator(ctx, validatorAddr)
require.True(t, found)
require.True(t, validator.GetStatus() == sdk.Unbonding, "%v", validator)
// should still be unbonding at time 6 seconds later
ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6))
EndBlocker(ctx, keeper)
validator, found = keeper.GetValidator(ctx, validatorAddr)
require.True(t, found)
require.True(t, validator.GetStatus() == sdk.Unbonding, "%v", validator)
// should be in unbonded state at time 7 seconds later
ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7))
EndBlocker(ctx, keeper)
validator, found = keeper.GetValidator(ctx, validatorAddr)
require.True(t, found)
require.True(t, validator.GetStatus() == sdk.Unbonded, "%v", validator)
}
func TestUnbondingPeriod(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
validatorAddr := sdk.ValAddress(keep.Addrs[0])

View File

@ -436,7 +436,7 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA
//______________________________________________________________________________________________________
// get info for begin functions: MinTime and CreationHeight
func (k Keeper) getBeginInfo(ctx sdk.Context, params types.Params, valSrcAddr sdk.ValAddress) (
func (k Keeper) getBeginInfo(ctx sdk.Context, valSrcAddr sdk.ValAddress) (
minTime time.Time, height int64, completeNow bool) {
validator, found := k.GetValidator(ctx, valSrcAddr)
@ -445,11 +445,11 @@ func (k Keeper) getBeginInfo(ctx sdk.Context, params types.Params, valSrcAddr sd
case !found || validator.Status == sdk.Bonded:
// the longest wait - just unbonding period from now
minTime = ctx.BlockHeader().Time.Add(params.UnbondingTime)
height = ctx.BlockHeader().Height
minTime = ctx.BlockHeader().Time.Add(k.UnbondingTime(ctx))
height = ctx.BlockHeight()
return minTime, height, false
case validator.IsUnbonded(ctx):
case validator.Status == sdk.Unbonded:
return minTime, height, true
case validator.Status == sdk.Unbonding:
@ -473,15 +473,14 @@ func (k Keeper) BeginUnbonding(ctx sdk.Context,
}
// create the unbonding delegation
params := k.GetParams(ctx)
minTime, height, completeNow := k.getBeginInfo(ctx, params, valAddr)
minTime, height, completeNow := k.getBeginInfo(ctx, valAddr)
returnAmount, err := k.unbond(ctx, delAddr, valAddr, sharesAmount)
if err != nil {
return types.UnbondingDelegation{}, err
}
balance := sdk.NewCoin(params.BondDenom, returnAmount.RoundInt())
balance := sdk.NewCoin(k.BondDenom(ctx), returnAmount.RoundInt())
// no need to create the ubd object just complete now
if completeNow {
@ -536,8 +535,7 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress,
return types.Redelegation{}, err
}
params := k.GetParams(ctx)
returnCoin := sdk.NewCoin(params.BondDenom, returnAmount.RoundInt())
returnCoin := sdk.Coin{k.BondDenom(ctx), returnAmount.RoundInt()}
dstValidator, found := k.GetValidator(ctx, valDstAddr)
if !found {
return types.Redelegation{}, types.ErrBadRedelegationDst(k.Codespace())
@ -548,7 +546,7 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress,
}
// create the unbonding delegation
minTime, height, completeNow := k.getBeginInfo(ctx, params, valSrcAddr)
minTime, height, completeNow := k.getBeginInfo(ctx, valSrcAddr)
if completeNow { // no need to create the redelegation object
return types.Redelegation{MinTime: minTime}, nil

View File

@ -374,12 +374,8 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) {
}
keeper.SetDelegation(ctx, delegation)
header := ctx.BlockHeader()
blockHeight := int64(10)
header.Height = blockHeight
blockTime := time.Unix(333, 0)
header.Time = blockTime
ctx = ctx.WithBlockHeader(header)
ctx = ctx.WithBlockHeight(10)
ctx = ctx.WithBlockTime(time.Unix(333, 0))
// unbond the all self-delegation to put validator in unbonding state
_, err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
@ -391,17 +387,12 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) {
validator, found := keeper.GetValidator(ctx, addrVals[0])
require.True(t, found)
require.Equal(t, blockHeight, validator.UnbondingHeight)
require.Equal(t, ctx.BlockHeight(), validator.UnbondingHeight)
params := keeper.GetParams(ctx)
require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingMinTime))
require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingMinTime))
// change the context to one which makes the validator considered unbonded
header = ctx.BlockHeader()
blockHeight2 := int64(20)
header.Height = blockHeight2
blockTime2 := time.Unix(444, 0).Add(params.UnbondingTime)
header.Time = blockTime2
ctx = ctx.WithBlockHeader(header)
// unbond the validator
keeper.unbondingToUnbonded(ctx, validator)
// unbond some of the other delegation's shares
_, err = keeper.BeginUnbonding(ctx, addrDels[0], addrVals[0], sdk.NewDec(6))
@ -696,12 +687,8 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) {
validator2 = TestingUpdateValidator(keeper, ctx, validator2)
require.Equal(t, sdk.Bonded, validator2.Status)
header := ctx.BlockHeader()
blockHeight := int64(10)
header.Height = blockHeight
blockTime := time.Unix(333, 0)
header.Time = blockTime
ctx = ctx.WithBlockHeader(header)
ctx = ctx.WithBlockHeight(10)
ctx = ctx.WithBlockTime(time.Unix(333, 0))
// unbond the all self-delegation to put validator in unbonding state
_, err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
@ -713,23 +700,18 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) {
validator, found := keeper.GetValidator(ctx, addrVals[0])
require.True(t, found)
require.Equal(t, blockHeight, validator.UnbondingHeight)
require.Equal(t, ctx.BlockHeight(), validator.UnbondingHeight)
params := keeper.GetParams(ctx)
require.True(t, blockTime.Add(params.UnbondingTime).Equal(validator.UnbondingMinTime))
require.True(t, ctx.BlockHeader().Time.Add(params.UnbondingTime).Equal(validator.UnbondingMinTime))
// change the context to one which makes the validator considered unbonded
header = ctx.BlockHeader()
blockHeight2 := int64(20)
header.Height = blockHeight2
blockTime2 := time.Unix(444, 0).Add(params.UnbondingTime)
header.Time = blockTime2
ctx = ctx.WithBlockHeader(header)
// unbond the validator
keeper.unbondingToUnbonded(ctx, validator)
// unbond some of the other delegation's shares
// redelegate some of the delegation's shares
_, err = keeper.BeginRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1], sdk.NewDec(6))
require.NoError(t, err)
// no ubd should have been found, coins should have been returned direcly to account
ubd, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
require.False(t, found, "%v", ubd)
// no red should have been found
red, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
require.False(t, found, "%v", red)
}

View File

@ -5,6 +5,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/cosmos/cosmos-sdk/x/stake/types"
)
@ -15,17 +16,19 @@ type Keeper struct {
cdc *codec.Codec
bankKeeper bank.Keeper
hooks sdk.StakingHooks
paramstore params.Subspace
// codespace
codespace sdk.CodespaceType
}
func NewKeeper(cdc *codec.Codec, key, tkey sdk.StoreKey, ck bank.Keeper, codespace sdk.CodespaceType) Keeper {
func NewKeeper(cdc *codec.Codec, key, tkey sdk.StoreKey, ck bank.Keeper, paramstore params.Subspace, codespace sdk.CodespaceType) Keeper {
keeper := Keeper{
storeKey: key,
storeTKey: tkey,
cdc: cdc,
bankKeeper: ck,
paramstore: paramstore.WithTypeTable(ParamTypeTable()),
hooks: nil,
codespace: codespace,
}
@ -48,29 +51,6 @@ func (k Keeper) Codespace() sdk.CodespaceType {
return k.codespace
}
//_________________________________________________________________________
// some generic reads/writes that don't need their own files
// load/save the global staking params
func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
store := ctx.KVStore(k.storeKey)
b := store.Get(ParamKey)
if b == nil {
panic("Stored params should not have been nil")
}
k.cdc.MustUnmarshalBinary(b, &params)
return
}
// set the params
func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
store := ctx.KVStore(k.storeKey)
b := k.cdc.MustMarshalBinary(params)
store.Set(ParamKey, b)
}
//_______________________________________________________________________
// load/save the pool

View File

@ -13,7 +13,8 @@ import (
//nolint
var (
// Keys for store prefixes
ParamKey = []byte{0x00} // key for parameters relating to staking
// TODO DEPRECATED: delete in next release and reorder keys
// ParamKey = []byte{0x00} // key for parameters relating to staking
PoolKey = []byte{0x01} // key for the staking pools
ValidatorsKey = []byte{0x02} // prefix for each key to a validator
ValidatorsByConsAddrKey = []byte{0x03} // prefix for each key to a validator index, by pubkey
@ -28,6 +29,7 @@ var (
RedelegationByValDstIndexKey = []byte{0x0C} // prefix for each key for an redelegation, by destination validator operator
UnbondingQueueKey = []byte{0x0D} // prefix for the timestamps in unbonding queue
RedelegationQueueKey = []byte{0x0E} // prefix for the timestamps in redelegations queue
ValidatorQueueKey = []byte{0x0F} // prefix for the timestamps in validator queue
)
const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch
@ -85,6 +87,12 @@ func getValidatorPowerRank(validator types.Validator) []byte {
return key
}
// gets the prefix for all unbonding delegations from a delegator
func GetValidatorQueueTimeKey(timestamp time.Time) []byte {
bz := types.MsgCdc.MustMarshalBinary(timestamp)
return append(ValidatorQueueKey, bz...)
}
//______________________________________________________________________________
// gets the key for delegator bond with validator

78
x/stake/keeper/params.go Normal file
View File

@ -0,0 +1,78 @@
package keeper
import (
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/cosmos/cosmos-sdk/x/stake/types"
)
// Default parameter namespace
const (
DefaultParamspace = "stake"
)
// ParamTable for stake module
func ParamTypeTable() params.TypeTable {
return params.NewTypeTable().RegisterParamSet(&types.Params{})
}
// InflationRateChange - Maximum annual change in inflation rate
func (k Keeper) InflationRateChange(ctx sdk.Context) (res sdk.Dec) {
k.paramstore.Get(ctx, types.KeyInflationRateChange, &res)
return
}
// InflationMax - Maximum inflation rate
func (k Keeper) InflationMax(ctx sdk.Context) (res sdk.Dec) {
k.paramstore.Get(ctx, types.KeyInflationMax, &res)
return
}
// InflationMin - Minimum inflation rate
func (k Keeper) InflationMin(ctx sdk.Context) (res sdk.Dec) {
k.paramstore.Get(ctx, types.KeyInflationMin, &res)
return
}
// GoalBonded - Goal of percent bonded atoms
func (k Keeper) GoalBonded(ctx sdk.Context) (res sdk.Dec) {
k.paramstore.Get(ctx, types.KeyGoalBonded, &res)
return
}
// UnbondingTime
func (k Keeper) UnbondingTime(ctx sdk.Context) (res time.Duration) {
k.paramstore.Get(ctx, types.KeyUnbondingTime, &res)
return
}
// MaxValidators - Maximum number of validators
func (k Keeper) MaxValidators(ctx sdk.Context) (res uint16) {
k.paramstore.Get(ctx, types.KeyMaxValidators, &res)
return
}
// BondDenom - Bondable coin denomination
func (k Keeper) BondDenom(ctx sdk.Context) (res string) {
k.paramstore.Get(ctx, types.KeyBondDenom, &res)
return
}
// Get all parameteras as types.Params
func (k Keeper) GetParams(ctx sdk.Context) (res types.Params) {
res.InflationRateChange = k.InflationRateChange(ctx)
res.InflationMax = k.InflationMax(ctx)
res.InflationMin = k.InflationMin(ctx)
res.GoalBonded = k.GoalBonded(ctx)
res.UnbondingTime = k.UnbondingTime(ctx)
res.MaxValidators = k.MaxValidators(ctx)
res.BondDenom = k.BondDenom(ctx)
return
}
// set the params
func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
k.paramstore.SetParamSet(ctx, &params)
}

View File

@ -46,7 +46,7 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh
}
// should not be slashing unbonded
if validator.IsUnbonded(ctx) {
if validator.Status == sdk.Unbonded {
panic(fmt.Sprintf("should not be slashing unbonded validator: %s", validator.GetOperator()))
}

View File

@ -19,6 +19,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/cosmos/cosmos-sdk/x/stake/types"
)
@ -90,12 +91,16 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context
keyStake := sdk.NewKVStoreKey("stake")
tkeyStake := sdk.NewTransientStoreKey("transient_stake")
keyAcc := sdk.NewKVStoreKey("acc")
keyParams := sdk.NewKVStoreKey("params")
tkeyParams := sdk.NewTransientStoreKey("transient_params")
db := dbm.NewMemDB()
ms := store.NewCommitMultiStore(db)
ms.MountStoreWithDB(tkeyStake, sdk.StoreTypeTransient, nil)
ms.MountStoreWithDB(keyStake, sdk.StoreTypeIAVL, db)
ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db)
ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db)
ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db)
err := ms.LoadLatestVersion()
require.Nil(t, err)
@ -106,8 +111,11 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context
keyAcc, // target store
auth.ProtoBaseAccount, // prototype
)
ck := bank.NewBaseKeeper(accountMapper)
keeper := NewKeeper(cdc, keyStake, tkeyStake, ck, types.DefaultCodespace)
pk := params.NewKeeper(cdc, keyParams, tkeyParams)
keeper := NewKeeper(cdc, keyStake, tkeyStake, ck, pk.Subspace(DefaultParamspace), types.DefaultCodespace)
keeper.SetPool(ctx, types.InitialPool())
keeper.SetParams(ctx, types.DefaultParams())
keeper.InitIntraTxCounter(ctx)
@ -116,7 +124,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context
for _, addr := range Addrs {
pool := keeper.GetPool(ctx)
_, _, err := ck.AddCoins(ctx, addr, sdk.Coins{
{keeper.GetParams(ctx).BondDenom, sdk.NewInt(initCoins)},
{keeper.BondDenom(ctx), sdk.NewInt(initCoins)},
})
require.Nil(t, err)
pool.LooseTokens = pool.LooseTokens.Add(sdk.NewDec(initCoins))

View File

@ -131,8 +131,9 @@ func (k Keeper) unbondedToBonded(ctx sdk.Context, validator types.Validator) typ
return k.bondValidator(ctx, validator)
}
// switches a validator from unbonding state to unbonded state
func (k Keeper) unbondingToUnbonded(ctx sdk.Context, validator types.Validator) types.Validator {
if validator.Status != sdk.Unbonded {
if validator.Status != sdk.Unbonding {
panic(fmt.Sprintf("bad state transition unbondingToBonded, validator: %v\n", validator))
}
return k.completeUnbondingValidator(ctx, validator)
@ -213,6 +214,9 @@ func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validat
k.SetValidatorByPowerIndex(ctx, validator, pool)
// Adds to unbonding validator queue
k.InsertValidatorQueue(ctx, validator)
// call the unbond hook if present
if k.hooks != nil {
k.hooks.OnValidatorBeginUnbonding(ctx, validator.ConsAddress())

View File

@ -3,6 +3,7 @@ package keeper
import (
"container/list"
"fmt"
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/stake/types"
@ -238,7 +239,7 @@ func (k Keeper) GetValidatorsBonded(ctx sdk.Context) (validators []types.Validat
store := ctx.KVStore(k.storeKey)
// add the actual validator power sorted store
maxValidators := k.GetParams(ctx).MaxValidators
maxValidators := k.MaxValidators(ctx)
validators = make([]types.Validator, maxValidators)
iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey)
@ -263,7 +264,7 @@ func (k Keeper) GetValidatorsBonded(ctx sdk.Context) (validators []types.Validat
// get the group of bonded validators sorted by power-rank
func (k Keeper) GetBondedValidatorsByPower(ctx sdk.Context) []types.Validator {
store := ctx.KVStore(k.storeKey)
maxValidators := k.GetParams(ctx).MaxValidators
maxValidators := k.MaxValidators(ctx)
validators := make([]types.Validator, maxValidators)
iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey)
@ -281,3 +282,69 @@ func (k Keeper) GetBondedValidatorsByPower(ctx sdk.Context) []types.Validator {
}
return validators[:i] // trim
}
// gets a specific validator queue timeslice. A timeslice is a slice of ValAddresses corresponding to unbonding validators
// that expire at a certain time.
func (k Keeper) GetValidatorQueueTimeSlice(ctx sdk.Context, timestamp time.Time) (valAddrs []sdk.ValAddress) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(GetValidatorQueueTimeKey(timestamp))
if bz == nil {
return []sdk.ValAddress{}
}
k.cdc.MustUnmarshalBinary(bz, &valAddrs)
return valAddrs
}
// Sets a specific validator queue timeslice.
func (k Keeper) SetValidatorQueueTimeSlice(ctx sdk.Context, timestamp time.Time, keys []sdk.ValAddress) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshalBinary(keys)
store.Set(GetValidatorQueueTimeKey(timestamp), bz)
}
// Insert an validator address to the appropriate timeslice in the validator queue
func (k Keeper) InsertValidatorQueue(ctx sdk.Context, val types.Validator) {
timeSlice := k.GetValidatorQueueTimeSlice(ctx, val.UnbondingMinTime)
if len(timeSlice) == 0 {
k.SetValidatorQueueTimeSlice(ctx, val.UnbondingMinTime, []sdk.ValAddress{val.OperatorAddr})
} else {
timeSlice = append(timeSlice, val.OperatorAddr)
k.SetValidatorQueueTimeSlice(ctx, val.UnbondingMinTime, timeSlice)
}
}
// Returns all the validator queue timeslices from time 0 until endTime
func (k Keeper) ValidatorQueueIterator(ctx sdk.Context, endTime time.Time) sdk.Iterator {
store := ctx.KVStore(k.storeKey)
return store.Iterator(ValidatorQueueKey, sdk.InclusiveEndBytes(GetValidatorQueueTimeKey(endTime)))
}
// Returns a concatenated list of all the timeslices before currTime, and deletes the timeslices from the queue
func (k Keeper) GetAllMatureValidatorQueue(ctx sdk.Context, currTime time.Time) (matureValsAddrs []sdk.ValAddress) {
// gets an iterator for all timeslices from time 0 until the current Blockheader time
validatorTimesliceIterator := k.ValidatorQueueIterator(ctx, ctx.BlockHeader().Time)
for ; validatorTimesliceIterator.Valid(); validatorTimesliceIterator.Next() {
timeslice := []sdk.ValAddress{}
k.cdc.MustUnmarshalBinary(validatorTimesliceIterator.Value(), &timeslice)
matureValsAddrs = append(matureValsAddrs, timeslice...)
}
return matureValsAddrs
}
// Unbonds all the unbonding validators that have finished their unbonding period
func (k Keeper) UnbondAllMatureValidatorQueue(ctx sdk.Context) {
store := ctx.KVStore(k.storeKey)
validatorTimesliceIterator := k.ValidatorQueueIterator(ctx, ctx.BlockHeader().Time)
for ; validatorTimesliceIterator.Valid(); validatorTimesliceIterator.Next() {
timeslice := []sdk.ValAddress{}
k.cdc.MustUnmarshalBinary(validatorTimesliceIterator.Value(), &timeslice)
for _, valAddr := range timeslice {
val, found := k.GetValidator(ctx, valAddr)
if !found || val.GetStatus() != sdk.Unbonding {
continue
}
k.unbondingToUnbonded(ctx, val)
}
store.Delete(validatorTimesliceIterator.Key())
}
}

View File

@ -11,6 +11,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/mock"
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/cosmos/cosmos-sdk/x/stake"
)
@ -23,7 +24,11 @@ func TestStakeWithRandomMessages(t *testing.T) {
bankKeeper := bank.NewBaseKeeper(mapper)
stakeKey := sdk.NewKVStoreKey("stake")
stakeTKey := sdk.NewTransientStoreKey("transient_stake")
stakeKeeper := stake.NewKeeper(mapp.Cdc, stakeKey, stakeTKey, bankKeeper, stake.DefaultCodespace)
paramsKey := sdk.NewKVStoreKey("params")
paramsTKey := sdk.NewTransientStoreKey("transient_params")
paramstore := params.NewKeeper(mapp.Cdc, paramsKey, paramsTKey).Subspace(stake.DefaultParamspace)
stakeKeeper := stake.NewKeeper(mapp.Cdc, stakeKey, stakeTKey, bankKeeper, paramstore, stake.DefaultCodespace)
mapp.Router().AddRoute("stake", stake.NewHandler(stakeKeeper))
mapp.SetEndBlocker(func(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
validatorUpdates := stake.EndBlocker(ctx, stakeKeeper)
@ -32,7 +37,7 @@ func TestStakeWithRandomMessages(t *testing.T) {
}
})
err := mapp.CompleteSetup(stakeKey, stakeTKey)
err := mapp.CompleteSetup(stakeKey, stakeTKey, paramsKey, paramsTKey)
if err != nil {
panic(err)
}

View File

@ -38,7 +38,6 @@ var (
GetValidatorsByPowerIndexKey = keeper.GetValidatorsByPowerIndexKey
GetDelegationKey = keeper.GetDelegationKey
GetDelegationsKey = keeper.GetDelegationsKey
ParamKey = keeper.ParamKey
PoolKey = keeper.PoolKey
ValidatorsKey = keeper.ValidatorsKey
ValidatorsByConsAddrKey = keeper.ValidatorsByConsAddrKey
@ -59,6 +58,14 @@ var (
GetREDsByDelToValDstIndexKey = keeper.GetREDsByDelToValDstIndexKey
TestingUpdateValidator = keeper.TestingUpdateValidator
DefaultParamspace = keeper.DefaultParamspace
KeyInflationRateChange = types.KeyInflationRateChange
KeyInflationMax = types.KeyInflationMax
KeyGoalBonded = types.KeyGoalBonded
KeyUnbondingTime = types.KeyUnbondingTime
KeyMaxValidators = types.KeyMaxValidators
KeyBondDenom = types.KeyBondDenom
DefaultParams = types.DefaultParams
InitialPool = types.InitialPool
NewValidator = types.NewValidator
@ -80,6 +87,18 @@ var (
NewQuerier = querier.NewQuerier
)
const (
QueryValidators = querier.QueryValidators
QueryValidator = querier.QueryValidator
QueryDelegator = querier.QueryDelegator
QueryDelegation = querier.QueryDelegation
QueryUnbondingDelegation = querier.QueryUnbondingDelegation
QueryDelegatorValidators = querier.QueryDelegatorValidators
QueryDelegatorValidator = querier.QueryDelegatorValidator
QueryPool = querier.QueryPool
QueryParameters = querier.QueryParameters
)
const (
DefaultCodespace = types.DefaultCodespace
CodeInvalidValidator = types.CodeInvalidValidator

View File

@ -7,6 +7,7 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/params"
)
const (
@ -21,6 +22,19 @@ const (
ValidatorUpdateDelay int64 = 1
)
// nolint - Keys for parameter access
var (
KeyInflationRateChange = []byte("InflationRateChange")
KeyInflationMax = []byte("InflationMax")
KeyInflationMin = []byte("InflationMin")
KeyGoalBonded = []byte("GoalBonded")
KeyUnbondingTime = []byte("UnbondingTime")
KeyMaxValidators = []byte("MaxValidators")
KeyBondDenom = []byte("BondDenom")
)
var _ params.ParamSet = (*Params)(nil)
// Params defines the high level settings for staking
type Params struct {
InflationRateChange sdk.Dec `json:"inflation_rate_change"` // maximum annual change in inflation rate
@ -34,6 +48,19 @@ type Params struct {
BondDenom string `json:"bond_denom"` // bondable coin denomination
}
// Implements params.ParamSet
func (p *Params) KeyValuePairs() params.KeyValuePairs {
return params.KeyValuePairs{
{KeyInflationRateChange, &p.InflationRateChange},
{KeyInflationMax, &p.InflationMax},
{KeyInflationMin, &p.InflationMin},
{KeyGoalBonded, &p.GoalBonded},
{KeyUnbondingTime, &p.UnbondingTime},
{KeyMaxValidators, &p.MaxValidators},
{KeyBondDenom, &p.BondDenom},
}
}
// Equal returns a boolean determining if two Param types are identical.
func (p Params) Equal(p2 Params) bool {
bz1 := MsgCdc.MustMarshalBinary(&p)

View File

@ -435,21 +435,6 @@ func (v Validator) BondedTokens() sdk.Dec {
return sdk.ZeroDec()
}
// TODO remove this once the validator queue logic is implemented
// Returns if the validator should be considered unbonded
func (v Validator) IsUnbonded(ctx sdk.Context) bool {
switch v.Status {
case sdk.Unbonded:
return true
case sdk.Unbonding:
ctxTime := ctx.BlockHeader().Time
if ctxTime.After(v.UnbondingMinTime) {
return true
}
}
return false
}
//______________________________________________________________________
// ensure fulfills the sdk validator types