Merge branch 'develop' into cwgoes/fix-signing-info-bugs
This commit is contained in:
commit
2c4d9a0be4
|
@ -56,6 +56,7 @@ jobs:
|
||||||
name: Get metalinter
|
name: Get metalinter
|
||||||
command: |
|
command: |
|
||||||
export PATH="$GOBIN:$PATH"
|
export PATH="$GOBIN:$PATH"
|
||||||
|
make get_tools
|
||||||
make get_dev_tools
|
make get_dev_tools
|
||||||
- run:
|
- run:
|
||||||
name: Lint source
|
name: Lint source
|
||||||
|
|
29
Makefile
29
Makefile
|
@ -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)
|
GCC := $(shell command -v gcc 2> /dev/null)
|
||||||
LEDGER_ENABLED ?= true
|
LEDGER_ENABLED ?= true
|
||||||
UNAME_S := $(shell uname -s)
|
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
|
all: get_tools get_vendor_deps install install_examples install_cosmos-sdk-cli test_lint test
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
|
@ -91,22 +95,27 @@ dist:
|
||||||
### Tools & dependencies
|
### Tools & dependencies
|
||||||
|
|
||||||
check_tools:
|
check_tools:
|
||||||
cd tools && $(MAKE) check_tools
|
@# https://stackoverflow.com/a/25668869
|
||||||
|
@echo "Found tools: $(foreach tool,$(notdir $(GOTOOLS)),\
|
||||||
check_dev_tools:
|
$(if $(shell which $(tool)),$(tool),$(error "No $(tool) in PATH")))"
|
||||||
cd tools && $(MAKE) check_dev_tools
|
|
||||||
|
|
||||||
update_tools:
|
update_tools:
|
||||||
cd tools && $(MAKE) update_tools
|
@echo "--> Updating tools to correct version"
|
||||||
|
./scripts/get_tools.sh
|
||||||
|
|
||||||
update_dev_tools:
|
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:
|
get_tools:
|
||||||
cd tools && $(MAKE) get_tools
|
@echo "--> Installing tools"
|
||||||
|
./scripts/get_tools.sh
|
||||||
|
|
||||||
get_dev_tools:
|
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:
|
get_vendor_deps:
|
||||||
@echo "--> Generating vendor directory via dep ensure"
|
@echo "--> Generating vendor directory via dep ensure"
|
||||||
|
@ -181,8 +190,8 @@ test_cover:
|
||||||
@export VERSION=$(VERSION); bash tests/test_cover.sh
|
@export VERSION=$(VERSION); bash tests/test_cover.sh
|
||||||
|
|
||||||
test_lint:
|
test_lint:
|
||||||
gometalinter.v2 --config=tools/gometalinter.json ./...
|
gometalinter --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 --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
|
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -d -s
|
||||||
dep status >> /dev/null
|
dep status >> /dev/null
|
||||||
!(grep -n branch Gopkg.toml)
|
!(grep -n branch Gopkg.toml)
|
||||||
|
|
|
@ -70,6 +70,7 @@ BREAKING CHANGES
|
||||||
* [x/staking] \#2236 more distribution hooks for distribution
|
* [x/staking] \#2236 more distribution hooks for distribution
|
||||||
* [x/stake] \#2394 Split up UpdateValidator into distinct state transitions applied only in EndBlock
|
* [x/stake] \#2394 Split up UpdateValidator into distinct state transitions applied only in EndBlock
|
||||||
* [x/slashing] \#2480 Fix signing info handling bugs & faulty slashing
|
* [x/slashing] \#2480 Fix signing info handling bugs & faulty slashing
|
||||||
|
* [x/stake] \#2412 Added an unbonding validator queue to EndBlock to automatically update validator.Status when finished Unbonding
|
||||||
|
|
||||||
* Tendermint
|
* Tendermint
|
||||||
* Update tendermint version from v0.23.0 to v0.25.0, notable changes
|
* Update tendermint version from v0.23.0 to v0.25.0, notable changes
|
||||||
|
@ -92,6 +93,7 @@ FEATURES
|
||||||
* [gaia-lite] [\#1953](https://github.com/cosmos/cosmos-sdk/issues/1953) Add /sign endpoint to sign transactions generated with `generate_only=true`.
|
* [gaia-lite] [\#1953](https://github.com/cosmos/cosmos-sdk/issues/1953) Add /sign endpoint to sign transactions generated with `generate_only=true`.
|
||||||
* [gaia-lite] [\#1954](https://github.com/cosmos/cosmos-sdk/issues/1954) Add /broadcast endpoint to broadcast transactions signed by the /sign endpoint.
|
* [gaia-lite] [\#1954](https://github.com/cosmos/cosmos-sdk/issues/1954) Add /broadcast endpoint to broadcast transactions signed by the /sign endpoint.
|
||||||
* [gaia-lite] [\#2113](https://github.com/cosmos/cosmos-sdk/issues/2113) Rename `/accounts/{address}/send` to `/bank/accounts/{address}/transfers`, rename `/accounts/{address}` to `/auth/accounts/{address}`
|
* [gaia-lite] [\#2113](https://github.com/cosmos/cosmos-sdk/issues/2113) Rename `/accounts/{address}/send` to `/bank/accounts/{address}/transfers`, rename `/accounts/{address}` to `/auth/accounts/{address}`
|
||||||
|
* [gaia-lite] [\#2478](https://github.com/cosmos/cosmos-sdk/issues/2478) Add query gov proposal's deposits endpoint
|
||||||
|
|
||||||
* Gaia CLI (`gaiacli`)
|
* Gaia CLI (`gaiacli`)
|
||||||
* [cli] Cmds to query staking pool and params
|
* [cli] Cmds to query staking pool and params
|
||||||
|
@ -171,6 +173,7 @@ IMPROVEMENTS
|
||||||
calls which includes dynamic consumption of value length.
|
calls which includes dynamic consumption of value length.
|
||||||
* [types/decimal] \#2378 - Added truncate functionality to decimal
|
* [types/decimal] \#2378 - Added truncate functionality to decimal
|
||||||
* [client] [\#1184](https://github.com/cosmos/cosmos-sdk/issues/1184) Remove unused `client/tx/sign.go`.
|
* [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
|
* Tendermint
|
||||||
|
|
||||||
|
|
|
@ -10,19 +10,19 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||||
|
p2p "github.com/tendermint/tendermint/p2p"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
cryptoKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
cryptoKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||||
p2p "github.com/tendermint/tendermint/p2p"
|
|
||||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
|
|
||||||
client "github.com/cosmos/cosmos-sdk/client"
|
client "github.com/cosmos/cosmos-sdk/client"
|
||||||
keys "github.com/cosmos/cosmos-sdk/client/keys"
|
keys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||||
rpc "github.com/cosmos/cosmos-sdk/client/rpc"
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
tests "github.com/cosmos/cosmos-sdk/tests"
|
tests "github.com/cosmos/cosmos-sdk/tests"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
@ -613,7 +613,7 @@ func TestSubmitProposal(t *testing.T) {
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
// create SubmitProposal TX
|
// create SubmitProposal TX
|
||||||
resultTx := doSubmitProposal(t, port, seed, name, password, addr)
|
resultTx := doSubmitProposal(t, port, seed, name, password, addr, 5)
|
||||||
tests.WaitForHeight(resultTx.Height+1, port)
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
// check if tx was committed
|
// check if tx was committed
|
||||||
|
@ -635,7 +635,7 @@ func TestDeposit(t *testing.T) {
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
// create SubmitProposal TX
|
// create SubmitProposal TX
|
||||||
resultTx := doSubmitProposal(t, port, seed, name, password, addr)
|
resultTx := doSubmitProposal(t, port, seed, name, password, addr, 5)
|
||||||
tests.WaitForHeight(resultTx.Height+1, port)
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
// check if tx was committed
|
// check if tx was committed
|
||||||
|
@ -650,7 +650,7 @@ func TestDeposit(t *testing.T) {
|
||||||
require.Equal(t, "Test", proposal.GetTitle())
|
require.Equal(t, "Test", proposal.GetTitle())
|
||||||
|
|
||||||
// create SubmitProposal TX
|
// create SubmitProposal TX
|
||||||
resultTx = doDeposit(t, port, seed, name, password, addr, proposalID)
|
resultTx = doDeposit(t, port, seed, name, password, addr, proposalID, 5)
|
||||||
tests.WaitForHeight(resultTx.Height+1, port)
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
// query proposal
|
// query proposal
|
||||||
|
@ -669,7 +669,7 @@ func TestVote(t *testing.T) {
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
// create SubmitProposal TX
|
// create SubmitProposal TX
|
||||||
resultTx := doSubmitProposal(t, port, seed, name, password, addr)
|
resultTx := doSubmitProposal(t, port, seed, name, password, addr, 5)
|
||||||
tests.WaitForHeight(resultTx.Height+1, port)
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
// check if tx was committed
|
// check if tx was committed
|
||||||
|
@ -684,7 +684,7 @@ func TestVote(t *testing.T) {
|
||||||
require.Equal(t, "Test", proposal.GetTitle())
|
require.Equal(t, "Test", proposal.GetTitle())
|
||||||
|
|
||||||
// create SubmitProposal TX
|
// create SubmitProposal TX
|
||||||
resultTx = doDeposit(t, port, seed, name, password, addr, proposalID)
|
resultTx = doDeposit(t, port, seed, name, password, addr, proposalID, 5)
|
||||||
tests.WaitForHeight(resultTx.Height+1, port)
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
// query proposal
|
// query proposal
|
||||||
|
@ -725,27 +725,52 @@ func TestProposalsQuery(t *testing.T) {
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
// Addr1 proposes (and deposits) proposals #1 and #2
|
// Addr1 proposes (and deposits) proposals #1 and #2
|
||||||
resultTx := doSubmitProposal(t, port, seed, name, password1, addr)
|
resultTx := doSubmitProposal(t, port, seed, name, password1, addr, 5)
|
||||||
var proposalID1 int64
|
var proposalID1 int64
|
||||||
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID1)
|
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID1)
|
||||||
tests.WaitForHeight(resultTx.Height+1, port)
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
resultTx = doSubmitProposal(t, port, seed, name, password1, addr)
|
resultTx = doSubmitProposal(t, port, seed, name, password1, addr, 5)
|
||||||
var proposalID2 int64
|
var proposalID2 int64
|
||||||
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID2)
|
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID2)
|
||||||
tests.WaitForHeight(resultTx.Height+1, port)
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
// Addr2 proposes (and deposits) proposals #3
|
// Addr2 proposes (and deposits) proposals #3
|
||||||
resultTx = doSubmitProposal(t, port, seed2, name2, password2, addr2)
|
resultTx = doSubmitProposal(t, port, seed2, name2, password2, addr2, 5)
|
||||||
var proposalID3 int64
|
var proposalID3 int64
|
||||||
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID3)
|
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID3)
|
||||||
tests.WaitForHeight(resultTx.Height+1, port)
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
// Addr2 deposits on proposals #2 & #3
|
// Addr2 deposits on proposals #2 & #3
|
||||||
resultTx = doDeposit(t, port, seed2, name2, password2, addr2, proposalID2)
|
resultTx = doDeposit(t, port, seed2, name2, password2, addr2, proposalID2, 5)
|
||||||
tests.WaitForHeight(resultTx.Height+1, port)
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
resultTx = doDeposit(t, port, seed2, name2, password2, addr2, proposalID3)
|
resultTx = doDeposit(t, port, seed2, name2, password2, addr2, proposalID3, 5)
|
||||||
tests.WaitForHeight(resultTx.Height+1, port)
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
|
// check deposits match proposal and individual deposits
|
||||||
|
deposits := getDeposits(t, port, proposalID1)
|
||||||
|
require.Len(t, deposits, 1)
|
||||||
|
deposit := getDeposit(t, port, proposalID1, addr)
|
||||||
|
require.Equal(t, deposit, deposits[0])
|
||||||
|
|
||||||
|
deposits = getDeposits(t, port, proposalID2)
|
||||||
|
require.Len(t, deposits, 2)
|
||||||
|
deposit = getDeposit(t, port, proposalID2, addr)
|
||||||
|
require.Equal(t, deposit, deposits[0])
|
||||||
|
deposit = getDeposit(t, port, proposalID2, addr2)
|
||||||
|
require.Equal(t, deposit, deposits[1])
|
||||||
|
|
||||||
|
deposits = getDeposits(t, port, proposalID3)
|
||||||
|
require.Len(t, deposits, 1)
|
||||||
|
deposit = getDeposit(t, port, proposalID3, addr2)
|
||||||
|
require.Equal(t, deposit, deposits[0])
|
||||||
|
|
||||||
|
// increasing the amount of the deposit should update the existing one
|
||||||
|
resultTx = doDeposit(t, port, seed, name, password1, addr, proposalID1, 1)
|
||||||
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
|
deposits = getDeposits(t, port, proposalID1)
|
||||||
|
require.Len(t, deposits, 1)
|
||||||
|
|
||||||
// Only proposals #1 should be in Deposit Period
|
// Only proposals #1 should be in Deposit Period
|
||||||
proposals := getProposalsFilterStatus(t, port, gov.StatusDepositPeriod)
|
proposals := getProposalsFilterStatus(t, port, gov.StatusDepositPeriod)
|
||||||
require.Len(t, proposals, 1)
|
require.Len(t, proposals, 1)
|
||||||
|
@ -1168,6 +1193,15 @@ func getProposal(t *testing.T, port string, proposalID int64) gov.Proposal {
|
||||||
return proposal
|
return proposal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getDeposits(t *testing.T, port string, proposalID int64) []gov.Deposit {
|
||||||
|
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/deposits", proposalID), nil)
|
||||||
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
var deposits []gov.Deposit
|
||||||
|
err := cdc.UnmarshalJSON([]byte(body), &deposits)
|
||||||
|
require.Nil(t, err)
|
||||||
|
return deposits
|
||||||
|
}
|
||||||
|
|
||||||
func getDeposit(t *testing.T, port string, proposalID int64, depositerAddr sdk.AccAddress) gov.Deposit {
|
func getDeposit(t *testing.T, port string, proposalID int64, depositerAddr sdk.AccAddress) gov.Deposit {
|
||||||
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/deposits/%s", proposalID, depositerAddr), nil)
|
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/deposits/%s", proposalID, depositerAddr), nil)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
@ -1245,7 +1279,7 @@ func getProposalsFilterStatus(t *testing.T, port string, status gov.ProposalStat
|
||||||
return proposals
|
return proposals
|
||||||
}
|
}
|
||||||
|
|
||||||
func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress) (resultTx ctypes.ResultBroadcastTxCommit) {
|
func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
|
||||||
|
|
||||||
acc := getAccount(t, port, proposerAddr)
|
acc := getAccount(t, port, proposerAddr)
|
||||||
accnum := acc.GetAccountNumber()
|
accnum := acc.GetAccountNumber()
|
||||||
|
@ -1259,7 +1293,7 @@ func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerA
|
||||||
"description": "test",
|
"description": "test",
|
||||||
"proposal_type": "Text",
|
"proposal_type": "Text",
|
||||||
"proposer": "%s",
|
"proposer": "%s",
|
||||||
"initial_deposit": [{ "denom": "steak", "amount": "5" }],
|
"initial_deposit": [{ "denom": "steak", "amount": "%d" }],
|
||||||
"base_req": {
|
"base_req": {
|
||||||
"name": "%s",
|
"name": "%s",
|
||||||
"password": "%s",
|
"password": "%s",
|
||||||
|
@ -1267,7 +1301,7 @@ func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerA
|
||||||
"account_number":"%d",
|
"account_number":"%d",
|
||||||
"sequence":"%d"
|
"sequence":"%d"
|
||||||
}
|
}
|
||||||
}`, proposerAddr, name, password, chainID, accnum, sequence))
|
}`, proposerAddr, amount, name, password, chainID, accnum, sequence))
|
||||||
res, body := Request(t, port, "POST", "/gov/proposals", jsonStr)
|
res, body := Request(t, port, "POST", "/gov/proposals", jsonStr)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
|
@ -1278,7 +1312,7 @@ func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerA
|
||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID int64) (resultTx ctypes.ResultBroadcastTxCommit) {
|
func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID int64, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
|
||||||
|
|
||||||
acc := getAccount(t, port, proposerAddr)
|
acc := getAccount(t, port, proposerAddr)
|
||||||
accnum := acc.GetAccountNumber()
|
accnum := acc.GetAccountNumber()
|
||||||
|
@ -1289,7 +1323,7 @@ func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk
|
||||||
// deposit on proposal
|
// deposit on proposal
|
||||||
jsonStr := []byte(fmt.Sprintf(`{
|
jsonStr := []byte(fmt.Sprintf(`{
|
||||||
"depositer": "%s",
|
"depositer": "%s",
|
||||||
"amount": [{ "denom": "steak", "amount": "5" }],
|
"amount": [{ "denom": "steak", "amount": "%d" }],
|
||||||
"base_req": {
|
"base_req": {
|
||||||
"name": "%s",
|
"name": "%s",
|
||||||
"password": "%s",
|
"password": "%s",
|
||||||
|
@ -1297,7 +1331,7 @@ func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk
|
||||||
"account_number":"%d",
|
"account_number":"%d",
|
||||||
"sequence": "%d"
|
"sequence": "%d"
|
||||||
}
|
}
|
||||||
}`, proposerAddr, name, password, chainID, accnum, sequence))
|
}`, proposerAddr, amount, name, password, chainID, accnum, sequence))
|
||||||
res, body := Request(t, port, "POST", fmt.Sprintf("/gov/proposals/%d/deposits", proposalID), jsonStr)
|
res, body := Request(t, port, "POST", fmt.Sprintf("/gov/proposals/%d/deposits", proposalID), jsonStr)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
|
|
|
@ -88,12 +88,41 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
|
||||||
|
|
||||||
// add handlers
|
// add handlers
|
||||||
app.bankKeeper = bank.NewBaseKeeper(app.accountMapper)
|
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.paramsKeeper = params.NewKeeper(
|
||||||
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.paramsKeeper.Getter(), app.RegisterCodespace(slashing.DefaultCodespace))
|
app.cdc,
|
||||||
app.stakeKeeper = app.stakeKeeper.WithHooks(app.slashingKeeper.Hooks())
|
app.keyParams, app.tkeyParams,
|
||||||
app.govKeeper = gov.NewKeeper(app.cdc, app.keyGov, app.paramsKeeper.Setter(), app.bankKeeper, app.stakeKeeper, app.RegisterCodespace(gov.DefaultCodespace))
|
)
|
||||||
app.feeCollectionKeeper = auth.NewFeeCollectionKeeper(app.cdc, app.keyFeeCollection)
|
|
||||||
|
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),
|
||||||
|
)
|
||||||
|
|
||||||
|
app.stakeKeeper = app.stakeKeeper.WithHooks(
|
||||||
|
app.slashingKeeper.Hooks(),
|
||||||
|
)
|
||||||
|
|
||||||
|
app.govKeeper = gov.NewKeeper(
|
||||||
|
app.cdc,
|
||||||
|
app.keyGov,
|
||||||
|
app.paramsKeeper, app.paramsKeeper.Subspace(gov.DefaultParamspace), app.bankKeeper, app.stakeKeeper,
|
||||||
|
app.RegisterCodespace(gov.DefaultCodespace),
|
||||||
|
)
|
||||||
|
|
||||||
|
app.feeCollectionKeeper = auth.NewFeeCollectionKeeper(
|
||||||
|
app.cdc,
|
||||||
|
app.keyFeeCollection,
|
||||||
|
)
|
||||||
|
|
||||||
// register message routes
|
// register message routes
|
||||||
app.Router().
|
app.Router().
|
||||||
|
@ -184,7 +213,7 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
||||||
}
|
}
|
||||||
|
|
||||||
// load the address to pubkey map
|
// 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)
|
gov.InitGenesis(ctx, app.govKeeper, genesisState.GovData)
|
||||||
err = GaiaValidateGenesisState(genesisState)
|
err = GaiaValidateGenesisState(genesisState)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/tendermint/tendermint/libs/db"
|
"github.com/tendermint/tendermint/libs/db"
|
||||||
|
@ -21,8 +22,9 @@ func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
genesisState := GenesisState{
|
genesisState := GenesisState{
|
||||||
Accounts: genaccs,
|
Accounts: genaccs,
|
||||||
StakeData: stake.DefaultGenesisState(),
|
StakeData: stake.DefaultGenesisState(),
|
||||||
|
SlashingData: slashing.DefaultGenesisState(),
|
||||||
}
|
}
|
||||||
|
|
||||||
stateBytes, err := codec.MarshalJSONIndent(gapp.cdc, genesisState)
|
stateBytes, err := codec.MarshalJSONIndent(gapp.cdc, genesisState)
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
|
@ -31,9 +32,10 @@ var (
|
||||||
|
|
||||||
// State to Unmarshal
|
// State to Unmarshal
|
||||||
type GenesisState struct {
|
type GenesisState struct {
|
||||||
Accounts []GenesisAccount `json:"accounts"`
|
Accounts []GenesisAccount `json:"accounts"`
|
||||||
StakeData stake.GenesisState `json:"stake"`
|
StakeData stake.GenesisState `json:"stake"`
|
||||||
GovData gov.GenesisState `json:"gov"`
|
GovData gov.GenesisState `json:"gov"`
|
||||||
|
SlashingData slashing.GenesisState `json:"slashing"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenesisAccount doesn't need pubkey or sequence
|
// GenesisAccount doesn't need pubkey or sequence
|
||||||
|
@ -168,6 +170,8 @@ func GaiaAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (genesisStat
|
||||||
// start with the default staking genesis state
|
// start with the default staking genesis state
|
||||||
stakeData := stake.DefaultGenesisState()
|
stakeData := stake.DefaultGenesisState()
|
||||||
|
|
||||||
|
slashingData := slashing.DefaultGenesisState()
|
||||||
|
|
||||||
// get genesis flag account information
|
// get genesis flag account information
|
||||||
genaccs := make([]GenesisAccount, len(appGenTxs))
|
genaccs := make([]GenesisAccount, len(appGenTxs))
|
||||||
for i, appGenTx := range appGenTxs {
|
for i, appGenTx := range appGenTxs {
|
||||||
|
@ -190,9 +194,10 @@ func GaiaAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (genesisStat
|
||||||
|
|
||||||
// create the final app state
|
// create the final app state
|
||||||
genesisState = GenesisState{
|
genesisState = GenesisState{
|
||||||
Accounts: genaccs,
|
Accounts: genaccs,
|
||||||
StakeData: stakeData,
|
StakeData: stakeData,
|
||||||
GovData: gov.DefaultGenesisState(),
|
GovData: gov.DefaultGenesisState(),
|
||||||
|
SlashingData: slashingData,
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||||
govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation"
|
govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation"
|
||||||
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
|
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||||
slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation"
|
slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation"
|
||||||
stake "github.com/cosmos/cosmos-sdk/x/stake"
|
stake "github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
stakesim "github.com/cosmos/cosmos-sdk/x/stake/simulation"
|
stakesim "github.com/cosmos/cosmos-sdk/x/stake/simulation"
|
||||||
|
@ -52,9 +53,11 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
||||||
Coins: coins,
|
Coins: coins,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
govGenesis := gov.DefaultGenesisState()
|
|
||||||
// Default genesis state
|
// Default genesis state
|
||||||
|
govGenesis := gov.DefaultGenesisState()
|
||||||
stakeGenesis := stake.DefaultGenesisState()
|
stakeGenesis := stake.DefaultGenesisState()
|
||||||
|
slashingGenesis := slashing.DefaultGenesisState()
|
||||||
var validators []stake.Validator
|
var validators []stake.Validator
|
||||||
var delegations []stake.Delegation
|
var delegations []stake.Delegation
|
||||||
// XXX Try different numbers of initially bonded validators
|
// XXX Try different numbers of initially bonded validators
|
||||||
|
@ -74,9 +77,10 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
||||||
stakeGenesis.Params.InflationMax = sdk.NewDec(0)
|
stakeGenesis.Params.InflationMax = sdk.NewDec(0)
|
||||||
stakeGenesis.Params.InflationMin = sdk.NewDec(0)
|
stakeGenesis.Params.InflationMin = sdk.NewDec(0)
|
||||||
genesis := GenesisState{
|
genesis := GenesisState{
|
||||||
Accounts: genesisAccounts,
|
Accounts: genesisAccounts,
|
||||||
StakeData: stakeGenesis,
|
StakeData: stakeGenesis,
|
||||||
GovData: govGenesis,
|
SlashingData: slashingGenesis,
|
||||||
|
GovData: govGenesis,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Marshal genesis
|
// Marshal genesis
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
)
|
)
|
||||||
|
@ -69,8 +70,9 @@ func NewTestGaiaAppGenState(
|
||||||
}
|
}
|
||||||
|
|
||||||
return GenesisState{
|
return GenesisState{
|
||||||
Accounts: genAccs,
|
Accounts: genAccs,
|
||||||
StakeData: stakeData,
|
StakeData: stakeData,
|
||||||
GovData: gov.DefaultGenesisState(),
|
SlashingData: slashing.DefaultGenesisState(),
|
||||||
|
GovData: gov.DefaultGenesisState(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,6 +135,7 @@ type GaiaApp struct {
|
||||||
tkeyStake *sdk.TransientStoreKey
|
tkeyStake *sdk.TransientStoreKey
|
||||||
keySlashing *sdk.KVStoreKey
|
keySlashing *sdk.KVStoreKey
|
||||||
keyParams *sdk.KVStoreKey
|
keyParams *sdk.KVStoreKey
|
||||||
|
tkeyParams *sdk.TransientStoreKey
|
||||||
|
|
||||||
// Manage getting and setting accounts
|
// Manage getting and setting accounts
|
||||||
accountMapper auth.AccountMapper
|
accountMapper auth.AccountMapper
|
||||||
|
@ -161,6 +162,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseAp
|
||||||
tkeyStake: sdk.NewTransientStoreKey("transient_stake"),
|
tkeyStake: sdk.NewTransientStoreKey("transient_stake"),
|
||||||
keySlashing: sdk.NewKVStoreKey("slashing"),
|
keySlashing: sdk.NewKVStoreKey("slashing"),
|
||||||
keyParams: sdk.NewKVStoreKey("params"),
|
keyParams: sdk.NewKVStoreKey("params"),
|
||||||
|
tkeyParams: sdk.NewTransientStoreKey("transient_params"),
|
||||||
}
|
}
|
||||||
|
|
||||||
// define the accountMapper
|
// define the accountMapper
|
||||||
|
@ -172,9 +174,9 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseAp
|
||||||
|
|
||||||
// add handlers
|
// add handlers
|
||||||
app.bankKeeper = bank.NewBaseKeeper(app.accountMapper)
|
app.bankKeeper = bank.NewBaseKeeper(app.accountMapper)
|
||||||
app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams)
|
app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams, app.tkeyParams)
|
||||||
app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.tkeyStake, app.bankKeeper, app.RegisterCodespace(stake.DefaultCodespace))
|
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.Getter(), app.RegisterCodespace(slashing.DefaultCodespace))
|
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace), app.RegisterCodespace(slashing.DefaultCodespace))
|
||||||
|
|
||||||
// register message routes
|
// register message routes
|
||||||
app.Router().
|
app.Router().
|
||||||
|
@ -186,7 +188,8 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseAp
|
||||||
app.SetBeginBlocker(app.BeginBlocker)
|
app.SetBeginBlocker(app.BeginBlocker)
|
||||||
app.SetEndBlocker(app.EndBlocker)
|
app.SetEndBlocker(app.EndBlocker)
|
||||||
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper))
|
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)
|
err := app.LoadLatestVersion(app.keyMain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cmn.Exit(err.Error())
|
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, "")
|
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{
|
return abci.ResponseInitChain{
|
||||||
Validators: validators,
|
Validators: validators,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,20 @@
|
||||||
# End-Block
|
# 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
|
## Validator Set Changes
|
||||||
|
|
||||||
The Tendermint validator set may be updated by state transitions that run at
|
The Tendermint validator set may be updated by state transitions that run at
|
||||||
|
|
|
@ -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
|
|
@ -13,13 +13,13 @@ import (
|
||||||
func newGasKVStore() KVStore {
|
func newGasKVStore() KVStore {
|
||||||
meter := sdk.NewGasMeter(1000)
|
meter := sdk.NewGasMeter(1000)
|
||||||
mem := dbStoreAdapter{dbm.NewMemDB()}
|
mem := dbStoreAdapter{dbm.NewMemDB()}
|
||||||
return NewGasKVStore(meter, sdk.DefaultGasConfig(), mem)
|
return NewGasKVStore(meter, sdk.KVGasConfig(), mem)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGasKVStoreBasic(t *testing.T) {
|
func TestGasKVStoreBasic(t *testing.T) {
|
||||||
mem := dbStoreAdapter{dbm.NewMemDB()}
|
mem := dbStoreAdapter{dbm.NewMemDB()}
|
||||||
meter := sdk.NewGasMeter(1000)
|
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(1)), "Expected `key1` to be empty")
|
||||||
st.Set(keyFmt(1), valFmt(1))
|
st.Set(keyFmt(1), valFmt(1))
|
||||||
require.Equal(t, valFmt(1), st.Get(keyFmt(1)))
|
require.Equal(t, valFmt(1), st.Get(keyFmt(1)))
|
||||||
|
@ -31,7 +31,7 @@ func TestGasKVStoreBasic(t *testing.T) {
|
||||||
func TestGasKVStoreIterator(t *testing.T) {
|
func TestGasKVStoreIterator(t *testing.T) {
|
||||||
mem := dbStoreAdapter{dbm.NewMemDB()}
|
mem := dbStoreAdapter{dbm.NewMemDB()}
|
||||||
meter := sdk.NewGasMeter(1000)
|
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(1)), "Expected `key1` to be empty")
|
||||||
require.Empty(t, st.Get(keyFmt(2)), "Expected `key2` to be empty")
|
require.Empty(t, st.Get(keyFmt(2)), "Expected `key2` to be empty")
|
||||||
st.Set(keyFmt(1), valFmt(1))
|
st.Set(keyFmt(1), valFmt(1))
|
||||||
|
@ -55,14 +55,14 @@ func TestGasKVStoreIterator(t *testing.T) {
|
||||||
func TestGasKVStoreOutOfGasSet(t *testing.T) {
|
func TestGasKVStoreOutOfGasSet(t *testing.T) {
|
||||||
mem := dbStoreAdapter{dbm.NewMemDB()}
|
mem := dbStoreAdapter{dbm.NewMemDB()}
|
||||||
meter := sdk.NewGasMeter(0)
|
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")
|
require.Panics(t, func() { st.Set(keyFmt(1), valFmt(1)) }, "Expected out-of-gas")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGasKVStoreOutOfGasIterator(t *testing.T) {
|
func TestGasKVStoreOutOfGasIterator(t *testing.T) {
|
||||||
mem := dbStoreAdapter{dbm.NewMemDB()}
|
mem := dbStoreAdapter{dbm.NewMemDB()}
|
||||||
meter := sdk.NewGasMeter(200)
|
meter := sdk.NewGasMeter(200)
|
||||||
st := NewGasKVStore(meter, sdk.DefaultGasConfig(), mem)
|
st := NewGasKVStore(meter, sdk.KVGasConfig(), mem)
|
||||||
st.Set(keyFmt(1), valFmt(1))
|
st.Set(keyFmt(1), valFmt(1))
|
||||||
iterator := st.Iterator(nil, nil)
|
iterator := st.Iterator(nil, nil)
|
||||||
iterator.Next()
|
iterator.Next()
|
||||||
|
|
|
@ -26,6 +26,9 @@ func cloneAppend(bz []byte, tail []byte) (res []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s prefixStore) key(key []byte) (res []byte) {
|
func (s prefixStore) key(key []byte) (res []byte) {
|
||||||
|
if key == nil {
|
||||||
|
panic("nil key on prefixStore")
|
||||||
|
}
|
||||||
res = cloneAppend(s.prefix, key)
|
res = cloneAppend(s.prefix, key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ type kvpair struct {
|
||||||
value []byte
|
value []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func setRandomKVPairs(t *testing.T, store KVStore) []kvpair {
|
func genRandomKVPairs(t *testing.T) []kvpair {
|
||||||
kvps := make([]kvpair, 20)
|
kvps := make([]kvpair, 20)
|
||||||
|
|
||||||
for i := 0; i < 20; i++ {
|
for i := 0; i < 20; i++ {
|
||||||
|
@ -25,17 +25,26 @@ func setRandomKVPairs(t *testing.T, store KVStore) []kvpair {
|
||||||
rand.Read(kvps[i].key)
|
rand.Read(kvps[i].key)
|
||||||
kvps[i].value = make([]byte, 32)
|
kvps[i].value = make([]byte, 32)
|
||||||
rand.Read(kvps[i].value)
|
rand.Read(kvps[i].value)
|
||||||
|
|
||||||
store.Set(kvps[i].key, kvps[i].value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return kvps
|
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) {
|
func testPrefixStore(t *testing.T, baseStore KVStore, prefix []byte) {
|
||||||
prefixStore := baseStore.Prefix(prefix)
|
prefixStore := baseStore.Prefix(prefix)
|
||||||
prefixPrefixStore := prefixStore.Prefix([]byte("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)
|
kvps := setRandomKVPairs(t, prefixPrefixStore)
|
||||||
|
|
||||||
for i := 0; i < 20; i++ {
|
for i := 0; i < 20; i++ {
|
||||||
|
@ -81,7 +90,7 @@ func TestCacheKVStorePrefix(t *testing.T) {
|
||||||
func TestGasKVStorePrefix(t *testing.T) {
|
func TestGasKVStorePrefix(t *testing.T) {
|
||||||
meter := sdk.NewGasMeter(100000000)
|
meter := sdk.NewGasMeter(100000000)
|
||||||
mem := dbStoreAdapter{dbm.NewMemDB()}
|
mem := dbStoreAdapter{dbm.NewMemDB()}
|
||||||
gasStore := NewGasKVStore(meter, sdk.DefaultGasConfig(), mem)
|
gasStore := NewGasKVStore(meter, sdk.KVGasConfig(), mem)
|
||||||
|
|
||||||
testPrefixStore(t, gasStore, []byte("test"))
|
testPrefixStore(t, gasStore, []byte("test"))
|
||||||
}
|
}
|
||||||
|
@ -109,6 +118,33 @@ func TestPrefixStoreIterate(t *testing.T) {
|
||||||
pIter.Close()
|
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) {
|
func TestPrefixStoreIteratorEdgeCase(t *testing.T) {
|
||||||
db := dbm.NewMemDB()
|
db := dbm.NewMemDB()
|
||||||
baseStore := dbStoreAdapter{db}
|
baseStore := dbStoreAdapter{db}
|
||||||
|
|
170
tools/Makefile
170
tools/Makefile
|
@ -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
|
|
|
@ -6,5 +6,5 @@
|
||||||
"Deadline": "500s",
|
"Deadline": "500s",
|
||||||
"Vendor": true,
|
"Vendor": true,
|
||||||
"Cyclo": 11,
|
"Cyclo": 11,
|
||||||
"Exclude": ["/usr/lib/go/src/", "client/lcd/statik/statik.go"]
|
"Exclude": ["/usr/lib/go/src/", "client/lcd/statik/statik.go", "vendor/*"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,6 @@ type Context struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a new context
|
// create a new context
|
||||||
// nolint: unparam
|
|
||||||
func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, logger log.Logger) Context {
|
func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, logger log.Logger) Context {
|
||||||
c := Context{
|
c := Context{
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
|
@ -74,7 +73,7 @@ func (c Context) Value(key interface{}) interface{} {
|
||||||
|
|
||||||
// KVStore fetches a KVStore from the MultiStore.
|
// KVStore fetches a KVStore from the MultiStore.
|
||||||
func (c Context) KVStore(key StoreKey) KVStore {
|
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.
|
// TransientStore fetches a TransientStore from the MultiStore.
|
||||||
|
@ -189,7 +188,9 @@ func (c Context) WithBlockTime(newTime time.Time) Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Context) WithBlockHeight(height int64) 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 {
|
func (c Context) WithConsensusParams(params *abci.ConsensusParams) Context {
|
||||||
|
|
|
@ -164,15 +164,16 @@ func TestContextWithCustom(t *testing.T) {
|
||||||
meter := types.NewGasMeter(10000)
|
meter := types.NewGasMeter(10000)
|
||||||
minFees := types.Coins{types.NewInt64Coin("feeCoin", 1)}
|
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).
|
WithBlockHeight(height).
|
||||||
WithChainID(chainid).
|
WithChainID(chainid).
|
||||||
WithTxBytes(txbytes).
|
WithTxBytes(txbytes).
|
||||||
WithVoteInfos(voteinfos).
|
WithVoteInfos(voteinfos).
|
||||||
WithGasMeter(meter).
|
WithGasMeter(meter).
|
||||||
WithMinimumFees(minFees)
|
WithMinimumFees(minFees)
|
||||||
|
|
||||||
require.Equal(t, header, ctx.BlockHeader())
|
|
||||||
require.Equal(t, height, ctx.BlockHeight())
|
require.Equal(t, height, ctx.BlockHeight())
|
||||||
require.Equal(t, chainid, ctx.ChainID())
|
require.Equal(t, chainid, ctx.ChainID())
|
||||||
require.Equal(t, ischeck, ctx.IsCheckTx())
|
require.Equal(t, ischeck, ctx.IsCheckTx())
|
||||||
|
|
|
@ -13,7 +13,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
cachedDefaultGasConfig = DefaultGasConfig()
|
cachedKVGasConfig = KVGasConfig()
|
||||||
cachedTransientGasConfig = TransientGasConfig()
|
cachedTransientGasConfig = TransientGasConfig()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -86,8 +86,8 @@ type GasConfig struct {
|
||||||
IterNextCostFlat Gas
|
IterNextCostFlat Gas
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultGasConfig returns a default gas config for KVStores.
|
// KVGasConfig returns a default gas config for KVStores.
|
||||||
func DefaultGasConfig() GasConfig {
|
func KVGasConfig() GasConfig {
|
||||||
return GasConfig{
|
return GasConfig{
|
||||||
HasCost: 10,
|
HasCost: 10,
|
||||||
DeleteCost: 10,
|
DeleteCost: 10,
|
||||||
|
@ -103,5 +103,5 @@ func DefaultGasConfig() GasConfig {
|
||||||
// TransientGasConfig returns a default gas config for TransientStores.
|
// TransientGasConfig returns a default gas config for TransientStores.
|
||||||
func TransientGasConfig() GasConfig {
|
func TransientGasConfig() GasConfig {
|
||||||
// TODO: define gasconfig for transient stores
|
// TODO: define gasconfig for transient stores
|
||||||
return DefaultGasConfig()
|
return KVGasConfig()
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,13 +31,12 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec)
|
||||||
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits", RestProposalID), depositHandlerFn(cdc, cliCtx)).Methods("POST")
|
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits", RestProposalID), depositHandlerFn(cdc, cliCtx)).Methods("POST")
|
||||||
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes", RestProposalID), voteHandlerFn(cdc, cliCtx)).Methods("POST")
|
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes", RestProposalID), voteHandlerFn(cdc, cliCtx)).Methods("POST")
|
||||||
|
|
||||||
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}", RestProposalID), queryProposalHandlerFn(cdc)).Methods("GET")
|
r.HandleFunc("/gov/proposals", queryProposalsWithParameterFn(cdc, cliCtx)).Methods("GET")
|
||||||
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits/{%s}", RestProposalID, RestDepositer), queryDepositHandlerFn(cdc)).Methods("GET")
|
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}", RestProposalID), queryProposalHandlerFn(cdc, cliCtx)).Methods("GET")
|
||||||
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes/{%s}", RestProposalID, RestVoter), queryVoteHandlerFn(cdc)).Methods("GET")
|
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits", RestProposalID), queryDepositsHandlerFn(cdc, cliCtx)).Methods("GET")
|
||||||
|
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits/{%s}", RestProposalID, RestDepositer), queryDepositHandlerFn(cdc, cliCtx)).Methods("GET")
|
||||||
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes", RestProposalID), queryVotesOnProposalHandlerFn(cdc)).Methods("GET")
|
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes", RestProposalID), queryVotesOnProposalHandlerFn(cdc, cliCtx)).Methods("GET")
|
||||||
|
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes/{%s}", RestProposalID, RestVoter), queryVoteHandlerFn(cdc, cliCtx)).Methods("GET")
|
||||||
r.HandleFunc("/gov/proposals", queryProposalsWithParameterFn(cdc)).Methods("GET")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type postProposalReq struct {
|
type postProposalReq struct {
|
||||||
|
@ -164,7 +163,7 @@ func voteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryProposalHandlerFn(cdc *codec.Codec) http.HandlerFunc {
|
func queryProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
strProposalID := vars[RestProposalID]
|
strProposalID := vars[RestProposalID]
|
||||||
|
@ -180,8 +179,6 @@ func queryProposalHandlerFn(cdc *codec.Codec) http.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
|
||||||
|
|
||||||
params := gov.QueryProposalParams{
|
params := gov.QueryProposalParams{
|
||||||
ProposalID: proposalID,
|
ProposalID: proposalID,
|
||||||
}
|
}
|
||||||
|
@ -198,11 +195,41 @@ func queryProposalHandlerFn(cdc *codec.Codec) http.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write(res)
|
utils.PostProcessResponse(w, cdc, res, cliCtx.Indent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryDepositHandlerFn(cdc *codec.Codec) http.HandlerFunc {
|
func queryDepositsHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
strProposalID := vars[RestProposalID]
|
||||||
|
|
||||||
|
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
params := gov.QueryDepositsParams{
|
||||||
|
ProposalID: proposalID,
|
||||||
|
}
|
||||||
|
|
||||||
|
bz, err := cdc.MarshalJSON(params)
|
||||||
|
if err != nil {
|
||||||
|
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := cliCtx.QueryWithData("custom/gov/deposits", bz)
|
||||||
|
if err != nil {
|
||||||
|
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.PostProcessResponse(w, cdc, res, cliCtx.Indent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func queryDepositHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
strProposalID := vars[RestProposalID]
|
strProposalID := vars[RestProposalID]
|
||||||
|
@ -232,8 +259,6 @@ func queryDepositHandlerFn(cdc *codec.Codec) http.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
|
||||||
|
|
||||||
params := gov.QueryDepositParams{
|
params := gov.QueryDepositParams{
|
||||||
ProposalID: proposalID,
|
ProposalID: proposalID,
|
||||||
Depositer: depositerAddr,
|
Depositer: depositerAddr,
|
||||||
|
@ -265,11 +290,11 @@ func queryDepositHandlerFn(cdc *codec.Codec) http.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write(res)
|
utils.PostProcessResponse(w, cdc, res, cliCtx.Indent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryVoteHandlerFn(cdc *codec.Codec) http.HandlerFunc {
|
func queryVoteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
strProposalID := vars[RestProposalID]
|
strProposalID := vars[RestProposalID]
|
||||||
|
@ -299,8 +324,6 @@ func queryVoteHandlerFn(cdc *codec.Codec) http.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
|
||||||
|
|
||||||
params := gov.QueryVoteParams{
|
params := gov.QueryVoteParams{
|
||||||
Voter: voterAddr,
|
Voter: voterAddr,
|
||||||
ProposalID: proposalID,
|
ProposalID: proposalID,
|
||||||
|
@ -335,12 +358,12 @@ func queryVoteHandlerFn(cdc *codec.Codec) http.HandlerFunc {
|
||||||
utils.WriteErrorResponse(w, http.StatusNotFound, err.Error())
|
utils.WriteErrorResponse(w, http.StatusNotFound, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Write(res)
|
utils.PostProcessResponse(w, cdc, res, cliCtx.Indent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: Split this functionality into helper functions to remove the above
|
// todo: Split this functionality into helper functions to remove the above
|
||||||
func queryVotesOnProposalHandlerFn(cdc *codec.Codec) http.HandlerFunc {
|
func queryVotesOnProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
strProposalID := vars[RestProposalID]
|
strProposalID := vars[RestProposalID]
|
||||||
|
@ -356,8 +379,6 @@ func queryVotesOnProposalHandlerFn(cdc *codec.Codec) http.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
|
||||||
|
|
||||||
params := gov.QueryVotesParams{
|
params := gov.QueryVotesParams{
|
||||||
ProposalID: proposalID,
|
ProposalID: proposalID,
|
||||||
}
|
}
|
||||||
|
@ -373,12 +394,12 @@ func queryVotesOnProposalHandlerFn(cdc *codec.Codec) http.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write(res)
|
utils.PostProcessResponse(w, cdc, res, cliCtx.Indent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: Split this functionality into helper functions to remove the above
|
// todo: Split this functionality into helper functions to remove the above
|
||||||
func queryProposalsWithParameterFn(cdc *codec.Codec) http.HandlerFunc {
|
func queryProposalsWithParameterFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
bechVoterAddr := r.URL.Query().Get(RestVoter)
|
bechVoterAddr := r.URL.Query().Get(RestVoter)
|
||||||
bechDepositerAddr := r.URL.Query().Get(RestDepositer)
|
bechDepositerAddr := r.URL.Query().Get(RestDepositer)
|
||||||
|
@ -430,20 +451,18 @@ func queryProposalsWithParameterFn(cdc *codec.Codec) http.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
|
||||||
|
|
||||||
res, err := cliCtx.QueryWithData("custom/gov/proposals", bz)
|
res, err := cliCtx.QueryWithData("custom/gov/proposals", bz)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write(res)
|
utils.PostProcessResponse(w, cdc, res, cliCtx.Indent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: Split this functionality into helper functions to remove the above
|
// todo: Split this functionality into helper functions to remove the above
|
||||||
func queryTallyOnProposalHandlerFn(cdc *codec.Codec) http.HandlerFunc {
|
func queryTallyOnProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
strProposalID := vars[RestProposalID]
|
strProposalID := vars[RestProposalID]
|
||||||
|
@ -461,8 +480,6 @@ func queryTallyOnProposalHandlerFn(cdc *codec.Codec) http.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
|
||||||
|
|
||||||
params := gov.QueryTallyParams{
|
params := gov.QueryTallyParams{
|
||||||
ProposalID: proposalID,
|
ProposalID: proposalID,
|
||||||
}
|
}
|
||||||
|
@ -480,6 +497,6 @@ func queryTallyOnProposalHandlerFn(cdc *codec.Codec) http.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write(res)
|
utils.PostProcessResponse(w, cdc, res, cliCtx.Indent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,17 +7,34 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/x/params"
|
"github.com/cosmos/cosmos-sdk/x/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// nolint
|
// Parameter store default namestore
|
||||||
const (
|
const (
|
||||||
ParamStoreKeyDepositProcedure = "gov/depositprocedure"
|
DefaultParamspace = "gov"
|
||||||
ParamStoreKeyVotingProcedure = "gov/votingprocedure"
|
|
||||||
ParamStoreKeyTallyingProcedure = "gov/tallyingprocedure"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 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
|
// Governance Keeper
|
||||||
type Keeper struct {
|
type Keeper struct {
|
||||||
// The reference to the ParamSetter to get and set Global Params
|
// The reference to the Param Keeper to get and set Global Params
|
||||||
ps params.Setter
|
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
|
// The reference to the CoinKeeper to modify balances
|
||||||
ck bank.Keeper
|
ck bank.Keeper
|
||||||
|
@ -43,15 +60,16 @@ type Keeper struct {
|
||||||
// - depositing funds into proposals, and activating upon sufficient funds being deposited
|
// - depositing funds into proposals, and activating upon sufficient funds being deposited
|
||||||
// - users voting on proposals, with weight proportional to stake in the system
|
// - users voting on proposals, with weight proportional to stake in the system
|
||||||
// - and tallying the result of the vote.
|
// - 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{
|
return Keeper{
|
||||||
storeKey: key,
|
storeKey: key,
|
||||||
ps: ps,
|
paramsKeeper: paramsKeeper,
|
||||||
ck: ck,
|
paramSpace: paramSpace.WithTypeTable(ParamTypeTable()),
|
||||||
ds: ds,
|
ck: ck,
|
||||||
vs: ds.GetValidatorSet(),
|
ds: ds,
|
||||||
cdc: cdc,
|
vs: ds.GetValidatorSet(),
|
||||||
codespace: codespace,
|
cdc: cdc,
|
||||||
|
codespace: codespace,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,7 +228,7 @@ func (keeper Keeper) activateVotingPeriod(ctx sdk.Context, proposal Proposal) {
|
||||||
// nolint: errcheck
|
// nolint: errcheck
|
||||||
func (keeper Keeper) GetDepositProcedure(ctx sdk.Context) DepositProcedure {
|
func (keeper Keeper) GetDepositProcedure(ctx sdk.Context) DepositProcedure {
|
||||||
var depositProcedure DepositProcedure
|
var depositProcedure DepositProcedure
|
||||||
keeper.ps.Get(ctx, ParamStoreKeyDepositProcedure, &depositProcedure)
|
keeper.paramSpace.Get(ctx, ParamStoreKeyDepositProcedure, &depositProcedure)
|
||||||
return depositProcedure
|
return depositProcedure
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,7 +236,7 @@ func (keeper Keeper) GetDepositProcedure(ctx sdk.Context) DepositProcedure {
|
||||||
// nolint: errcheck
|
// nolint: errcheck
|
||||||
func (keeper Keeper) GetVotingProcedure(ctx sdk.Context) VotingProcedure {
|
func (keeper Keeper) GetVotingProcedure(ctx sdk.Context) VotingProcedure {
|
||||||
var votingProcedure VotingProcedure
|
var votingProcedure VotingProcedure
|
||||||
keeper.ps.Get(ctx, ParamStoreKeyVotingProcedure, &votingProcedure)
|
keeper.paramSpace.Get(ctx, ParamStoreKeyVotingProcedure, &votingProcedure)
|
||||||
return votingProcedure
|
return votingProcedure
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,23 +244,23 @@ func (keeper Keeper) GetVotingProcedure(ctx sdk.Context) VotingProcedure {
|
||||||
// nolint: errcheck
|
// nolint: errcheck
|
||||||
func (keeper Keeper) GetTallyingProcedure(ctx sdk.Context) TallyingProcedure {
|
func (keeper Keeper) GetTallyingProcedure(ctx sdk.Context) TallyingProcedure {
|
||||||
var tallyingProcedure TallyingProcedure
|
var tallyingProcedure TallyingProcedure
|
||||||
keeper.ps.Get(ctx, ParamStoreKeyTallyingProcedure, &tallyingProcedure)
|
keeper.paramSpace.Get(ctx, ParamStoreKeyTallyingProcedure, &tallyingProcedure)
|
||||||
return tallyingProcedure
|
return tallyingProcedure
|
||||||
}
|
}
|
||||||
|
|
||||||
// nolint: errcheck
|
// nolint: errcheck
|
||||||
func (keeper Keeper) setDepositProcedure(ctx sdk.Context, depositProcedure DepositProcedure) {
|
func (keeper Keeper) setDepositProcedure(ctx sdk.Context, depositProcedure DepositProcedure) {
|
||||||
keeper.ps.Set(ctx, ParamStoreKeyDepositProcedure, &depositProcedure)
|
keeper.paramSpace.Set(ctx, ParamStoreKeyDepositProcedure, &depositProcedure)
|
||||||
}
|
}
|
||||||
|
|
||||||
// nolint: errcheck
|
// nolint: errcheck
|
||||||
func (keeper Keeper) setVotingProcedure(ctx sdk.Context, votingProcedure VotingProcedure) {
|
func (keeper Keeper) setVotingProcedure(ctx sdk.Context, votingProcedure VotingProcedure) {
|
||||||
keeper.ps.Set(ctx, ParamStoreKeyVotingProcedure, &votingProcedure)
|
keeper.paramSpace.Set(ctx, ParamStoreKeyVotingProcedure, &votingProcedure)
|
||||||
}
|
}
|
||||||
|
|
||||||
// nolint: errcheck
|
// nolint: errcheck
|
||||||
func (keeper Keeper) setTallyingProcedure(ctx sdk.Context, tallyingProcedure TallyingProcedure) {
|
func (keeper Keeper) setTallyingProcedure(ctx sdk.Context, tallyingProcedure TallyingProcedure) {
|
||||||
keeper.ps.Set(ctx, ParamStoreKeyTallyingProcedure, &tallyingProcedure)
|
keeper.paramSpace.Set(ctx, ParamStoreKeyTallyingProcedure, &tallyingProcedure)
|
||||||
}
|
}
|
||||||
|
|
||||||
// =====================================================
|
// =====================================================
|
||||||
|
|
|
@ -118,7 +118,7 @@ type QueryDepositsParams struct {
|
||||||
|
|
||||||
// nolint: unparam
|
// nolint: unparam
|
||||||
func queryDeposits(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
func queryDeposits(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
||||||
var params QueryDepositParams
|
var params QueryDepositsParams
|
||||||
err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms)
|
err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms)
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
return []byte{}, sdk.ErrUnknownRequest(fmt.Sprintf("incorrectly formatted request data - %s", err2.Error()))
|
return []byte{}, sdk.ErrUnknownRequest(fmt.Sprintf("incorrectly formatted request data - %s", err2.Error()))
|
||||||
|
|
|
@ -23,21 +23,23 @@ func TestGovWithRandomMessages(t *testing.T) {
|
||||||
bank.RegisterCodec(mapp.Cdc)
|
bank.RegisterCodec(mapp.Cdc)
|
||||||
gov.RegisterCodec(mapp.Cdc)
|
gov.RegisterCodec(mapp.Cdc)
|
||||||
mapper := mapp.AccountMapper
|
mapper := mapp.AccountMapper
|
||||||
|
|
||||||
bankKeeper := bank.NewBaseKeeper(mapper)
|
bankKeeper := bank.NewBaseKeeper(mapper)
|
||||||
stakeKey := sdk.NewKVStoreKey("stake")
|
stakeKey := sdk.NewKVStoreKey("stake")
|
||||||
stakeTKey := sdk.NewTransientStoreKey("transient_stake")
|
stakeTKey := sdk.NewTransientStoreKey("transient_stake")
|
||||||
stakeKeeper := stake.NewKeeper(mapp.Cdc, stakeKey, stakeTKey, bankKeeper, stake.DefaultCodespace)
|
|
||||||
paramKey := sdk.NewKVStoreKey("params")
|
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")
|
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.Router().AddRoute("gov", gov.NewHandler(govKeeper))
|
||||||
mapp.SetEndBlocker(func(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
|
mapp.SetEndBlocker(func(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
|
||||||
gov.EndBlocker(ctx, govKeeper)
|
gov.EndBlocker(ctx, govKeeper)
|
||||||
return abci.ResponseEndBlock{}
|
return abci.ResponseEndBlock{}
|
||||||
})
|
})
|
||||||
|
|
||||||
err := mapp.CompleteSetup(stakeKey, stakeTKey, paramKey, govKey)
|
err := mapp.CompleteSetup(stakeKey, stakeTKey, paramKey, paramTKey, govKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,20 +27,22 @@ func getMockApp(t *testing.T, numGenAccs int) (*mock.App, Keeper, stake.Keeper,
|
||||||
RegisterCodec(mapp.Cdc)
|
RegisterCodec(mapp.Cdc)
|
||||||
|
|
||||||
keyGlobalParams := sdk.NewKVStoreKey("params")
|
keyGlobalParams := sdk.NewKVStoreKey("params")
|
||||||
|
tkeyGlobalParams := sdk.NewTransientStoreKey("transient_params")
|
||||||
keyStake := sdk.NewKVStoreKey("stake")
|
keyStake := sdk.NewKVStoreKey("stake")
|
||||||
tkeyStake := sdk.NewTransientStoreKey("transient_stake")
|
tkeyStake := sdk.NewTransientStoreKey("transient_stake")
|
||||||
keyGov := sdk.NewKVStoreKey("gov")
|
keyGov := sdk.NewKVStoreKey("gov")
|
||||||
|
|
||||||
pk := params.NewKeeper(mapp.Cdc, keyGlobalParams)
|
pk := params.NewKeeper(mapp.Cdc, keyGlobalParams, tkeyGlobalParams)
|
||||||
ck := bank.NewBaseKeeper(mapp.AccountMapper)
|
ck := bank.NewBaseKeeper(mapp.AccountMapper)
|
||||||
sk := stake.NewKeeper(mapp.Cdc, keyStake, tkeyStake, ck, mapp.RegisterCodespace(stake.DefaultCodespace))
|
sk := stake.NewKeeper(mapp.Cdc, keyStake, tkeyStake, ck, pk.Subspace(stake.DefaultParamspace), mapp.RegisterCodespace(stake.DefaultCodespace))
|
||||||
keeper := NewKeeper(mapp.Cdc, keyGov, pk.Setter(), ck, sk, DefaultCodespace)
|
keeper := NewKeeper(mapp.Cdc, keyGov, pk, pk.Subspace("testgov"), ck, sk, DefaultCodespace)
|
||||||
|
|
||||||
mapp.Router().AddRoute("gov", NewHandler(keeper))
|
mapp.Router().AddRoute("gov", NewHandler(keeper))
|
||||||
|
|
||||||
mapp.SetEndBlocker(getEndBlocker(keeper))
|
mapp.SetEndBlocker(getEndBlocker(keeper))
|
||||||
mapp.SetInitChainer(getInitChainer(mapp, keeper, sk))
|
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)})
|
genAccs, addrs, pubKeys, privKeys := mock.CreateGenAccounts(numGenAccs, sdk.Coins{sdk.NewInt64Coin("steak", 42)})
|
||||||
|
|
||||||
|
|
|
@ -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, ¶m)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
*/
|
|
@ -1,406 +1,57 @@
|
||||||
package params
|
package params
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
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 {
|
type Keeper struct {
|
||||||
cdc *codec.Codec
|
cdc *codec.Codec
|
||||||
key sdk.StoreKey
|
key sdk.StoreKey
|
||||||
|
tkey sdk.StoreKey
|
||||||
|
|
||||||
|
spaces map[string]*Subspace
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewKeeper constructs a new Keeper
|
// NewKeeper constructs a params keeper
|
||||||
func NewKeeper(cdc *codec.Codec, key sdk.StoreKey) Keeper {
|
func NewKeeper(cdc *codec.Codec, key *sdk.KVStoreKey, tkey *sdk.TransientStoreKey) (k Keeper) {
|
||||||
return Keeper{
|
k = Keeper{
|
||||||
cdc: cdc,
|
cdc: cdc,
|
||||||
key: key,
|
key: key,
|
||||||
}
|
tkey: tkey,
|
||||||
}
|
|
||||||
|
|
||||||
// InitKeeper constructs a new Keeper with initial parameters
|
spaces: make(map[string]*Subspace),
|
||||||
// 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])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return k
|
return k
|
||||||
}
|
}
|
||||||
|
|
||||||
// get automatically unmarshalls parameter to pointer
|
// Allocate subspace used for keepers
|
||||||
func (k Keeper) get(ctx sdk.Context, key string, ptr interface{}) error {
|
func (k Keeper) Subspace(spacename string) Subspace {
|
||||||
store := ctx.KVStore(k.key)
|
_, ok := k.spaces[spacename]
|
||||||
bz := store.Get([]byte(key))
|
if ok {
|
||||||
return k.cdc.UnmarshalBinary(bz, ptr)
|
panic("subspace already occupied")
|
||||||
}
|
|
||||||
|
|
||||||
// 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")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bz, err := k.cdc.MarshalBinary(param)
|
if spacename == "" {
|
||||||
if err != nil {
|
panic("cannot use empty string for subspace")
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
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
|
// Get existing substore from keeper
|
||||||
func (k Keeper) setRaw(ctx sdk.Context, key string, param []byte) {
|
func (k Keeper) GetSubspace(storename string) (Subspace, bool) {
|
||||||
store := ctx.KVStore(k.key)
|
space, ok := k.spaces[storename]
|
||||||
store.Set([]byte(key), param)
|
if !ok {
|
||||||
}
|
return Subspace{}, false
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
}
|
||||||
|
return *space, ok
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package params
|
package params
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
dbm "github.com/tendermint/tendermint/libs/db"
|
dbm "github.com/tendermint/tendermint/libs/db"
|
||||||
|
@ -14,15 +15,30 @@ import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
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()
|
db := dbm.NewMemDB()
|
||||||
cms := store.NewCommitMultiStore(db)
|
cms := store.NewCommitMultiStore(db)
|
||||||
cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db)
|
cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db)
|
||||||
|
cms.MountStoreWithDB(tkey, sdk.StoreTypeTransient, db)
|
||||||
cms.LoadLatestVersion()
|
cms.LoadLatestVersion()
|
||||||
ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger())
|
ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger())
|
||||||
return ctx
|
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) {
|
func TestKeeper(t *testing.T) {
|
||||||
kvs := []struct {
|
kvs := []struct {
|
||||||
key string
|
key string
|
||||||
|
@ -33,248 +49,120 @@ func TestKeeper(t *testing.T) {
|
||||||
{"key3", 182},
|
{"key3", 182},
|
||||||
{"key4", 17582},
|
{"key4", 17582},
|
||||||
{"key5", 2768554},
|
{"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")
|
skey := sdk.NewKVStoreKey("test")
|
||||||
ctx := defaultContext(skey)
|
tkey := sdk.NewTransientStoreKey("transient_test")
|
||||||
setter := NewKeeper(codec.New(), skey).Setter()
|
ctx := defaultContext(skey, tkey)
|
||||||
|
store := NewKeeper(codec.New(), skey, tkey).Subspace("test").WithTypeTable(table)
|
||||||
|
|
||||||
for _, kv := range kvs {
|
for i, kv := range kvs {
|
||||||
err := setter.Set(ctx, kv.key, kv.param)
|
require.NotPanics(t, func() { store.Set(ctx, []byte(kv.key), kv.param) }, "store.Set panics, tc #%d", i)
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, kv := range kvs {
|
for i, kv := range kvs {
|
||||||
var param int64
|
var param int64
|
||||||
err := setter.Get(ctx, kv.key, ¶m)
|
require.NotPanics(t, func() { store.Get(ctx, []byte(kv.key), ¶m) }, "store.Get panics, tc #%d", i)
|
||||||
assert.Nil(t, err)
|
require.Equal(t, kv.param, param, "stored param not equal, tc #%d", i)
|
||||||
assert.Equal(t, kv.param, param)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cdc := codec.New()
|
cdc := codec.New()
|
||||||
for _, kv := range kvs {
|
for i, kv := range kvs {
|
||||||
var param int64
|
var param int64
|
||||||
bz := setter.GetRaw(ctx, kv.key)
|
bz := store.GetRaw(ctx, []byte(kv.key))
|
||||||
err := cdc.UnmarshalBinary(bz, ¶m)
|
err := cdc.UnmarshalJSON(bz, ¶m)
|
||||||
assert.Nil(t, err)
|
require.Nil(t, err, "err is not nil, tc #%d", i)
|
||||||
assert.Equal(t, kv.param, param)
|
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
|
var param bool
|
||||||
err := setter.Get(ctx, kv.key, ¶m)
|
require.Panics(t, func() { store.Get(ctx, []byte(kv.key), ¶m) }, "invalid store.Get not panics, tc #%d", i)
|
||||||
assert.NotNil(t, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, kv := range kvs {
|
for i, kv := range kvs {
|
||||||
err := setter.Set(ctx, kv.key, true)
|
require.Panics(t, func() { store.Set(ctx, []byte(kv.key), true) }, "invalid store.Set not panics, tc #%d", i)
|
||||||
assert.NotNil(t, err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetter(t *testing.T) {
|
func TestGet(t *testing.T) {
|
||||||
key := sdk.NewKVStoreKey("test")
|
key := sdk.NewKVStoreKey("test")
|
||||||
ctx := defaultContext(key)
|
tkey := sdk.NewTransientStoreKey("transient_test")
|
||||||
keeper := NewKeeper(codec.New(), key)
|
ctx := defaultContext(key, tkey)
|
||||||
|
keeper := NewKeeper(createTestCodec(), key, tkey)
|
||||||
g := keeper.Getter()
|
|
||||||
s := keeper.Setter()
|
|
||||||
|
|
||||||
kvs := []struct {
|
kvs := []struct {
|
||||||
key string
|
key string
|
||||||
param interface{}
|
param interface{}
|
||||||
|
zero interface{}
|
||||||
|
ptr interface{}
|
||||||
}{
|
}{
|
||||||
{"string", "test"},
|
{"string", "test", "", new(string)},
|
||||||
{"bool", true},
|
{"bool", true, false, new(bool)},
|
||||||
{"int16", int16(1)},
|
{"int16", int16(1), int16(0), new(int16)},
|
||||||
{"int32", int32(1)},
|
{"int32", int32(1), int32(0), new(int32)},
|
||||||
{"int64", int64(1)},
|
{"int64", int64(1), int64(0), new(int64)},
|
||||||
{"uint16", uint16(1)},
|
{"uint16", uint16(1), uint16(0), new(uint16)},
|
||||||
{"uint32", uint32(1)},
|
{"uint32", uint32(1), uint32(0), new(uint32)},
|
||||||
{"uint64", uint64(1)},
|
{"uint64", uint64(1), uint64(0), new(uint64)},
|
||||||
{"int", sdk.NewInt(1)},
|
{"int", sdk.NewInt(1), *new(sdk.Int), new(sdk.Int)},
|
||||||
{"uint", sdk.NewUint(1)},
|
{"uint", sdk.NewUint(1), *new(sdk.Uint), new(sdk.Uint)},
|
||||||
{"rat", sdk.NewDec(1)},
|
{"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") })
|
table := NewTypeTable(
|
||||||
assert.NotPanics(t, func() { s.SetBool(ctx, kvs[1].key, true) })
|
[]byte("string"), string(""),
|
||||||
assert.NotPanics(t, func() { s.SetInt16(ctx, kvs[2].key, int16(1)) })
|
[]byte("bool"), bool(false),
|
||||||
assert.NotPanics(t, func() { s.SetInt32(ctx, kvs[3].key, int32(1)) })
|
[]byte("int16"), int16(0),
|
||||||
assert.NotPanics(t, func() { s.SetInt64(ctx, kvs[4].key, int64(1)) })
|
[]byte("int32"), int32(0),
|
||||||
assert.NotPanics(t, func() { s.SetUint16(ctx, kvs[5].key, uint16(1)) })
|
[]byte("int64"), int64(0),
|
||||||
assert.NotPanics(t, func() { s.SetUint32(ctx, kvs[6].key, uint32(1)) })
|
[]byte("uint16"), uint16(0),
|
||||||
assert.NotPanics(t, func() { s.SetUint64(ctx, kvs[7].key, uint64(1)) })
|
[]byte("uint32"), uint32(0),
|
||||||
assert.NotPanics(t, func() { s.SetInt(ctx, kvs[8].key, sdk.NewInt(1)) })
|
[]byte("uint64"), uint64(0),
|
||||||
assert.NotPanics(t, func() { s.SetUint(ctx, kvs[9].key, sdk.NewUint(1)) })
|
[]byte("int"), sdk.Int{},
|
||||||
assert.NotPanics(t, func() { s.SetDec(ctx, kvs[10].key, sdk.NewDec(1)) })
|
[]byte("uint"), sdk.Uint{},
|
||||||
|
[]byte("dec"), sdk.Dec{},
|
||||||
|
[]byte("struct"), s{},
|
||||||
|
)
|
||||||
|
|
||||||
var res interface{}
|
store := keeper.Subspace("test").WithTypeTable(table)
|
||||||
var err error
|
|
||||||
|
|
||||||
// String
|
for i, kv := range kvs {
|
||||||
def0 := "default"
|
require.False(t, store.Modified(ctx, []byte(kv.key)), "store.Modified returns true before setting, tc #%d", i)
|
||||||
res, err = g.GetString(ctx, kvs[0].key)
|
require.NotPanics(t, func() { store.Set(ctx, []byte(kv.key), kv.param) }, "store.Set panics, tc #%d", i)
|
||||||
assert.Nil(t, err)
|
require.True(t, store.Modified(ctx, []byte(kv.key)), "store.Modified returns false after setting, tc #%d", i)
|
||||||
assert.Equal(t, kvs[0].param, res)
|
}
|
||||||
|
|
||||||
_, err = g.GetString(ctx, "invalid")
|
for i, kv := range kvs {
|
||||||
assert.NotNil(t, err)
|
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)
|
require.NotPanics(t, func() { store.GetIfExists(ctx, []byte(kv.key), kv.ptr) }, "store.GetIfExists panics, tc #%d", i)
|
||||||
assert.Equal(t, kvs[0].param, res)
|
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)
|
require.Panics(t, func() { store.Get(ctx, []byte("invalid"), kv.ptr) }, "invalid store.Get not panics when no value exists, tc #%d", i)
|
||||||
assert.Equal(t, def0, res)
|
require.Equal(t, kv.param, reflect.ValueOf(kv.ptr).Elem().Interface(), "invalid store.Get unmarshalls when no value existt, tc #%d", i)
|
||||||
|
|
||||||
// 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(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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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...)
|
||||||
|
}
|
|
@ -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)
|
||||||
|
*/
|
|
@ -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
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -28,18 +28,21 @@ func getMockApp(t *testing.T) (*mock.App, stake.Keeper, Keeper) {
|
||||||
keyStake := sdk.NewKVStoreKey("stake")
|
keyStake := sdk.NewKVStoreKey("stake")
|
||||||
tkeyStake := sdk.NewTransientStoreKey("transient_stake")
|
tkeyStake := sdk.NewTransientStoreKey("transient_stake")
|
||||||
keySlashing := sdk.NewKVStoreKey("slashing")
|
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("stake", stake.NewHandler(stakeKeeper))
|
||||||
mapp.Router().AddRoute("slashing", NewHandler(keeper))
|
mapp.Router().AddRoute("slashing", NewHandler(keeper))
|
||||||
|
|
||||||
mapp.SetEndBlocker(getEndBlocker(stakeKeeper))
|
mapp.SetEndBlocker(getEndBlocker(stakeKeeper))
|
||||||
mapp.SetInitChainer(getInitChainer(mapp, 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
|
return mapp, stakeKeeper, keeper
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,24 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// InitGenesis initializes the keeper's address to pubkey map.
|
// GenesisState - all slashing state that must be provided at genesis
|
||||||
func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) {
|
type GenesisState struct {
|
||||||
for _, validator := range data.Validators {
|
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())
|
keeper.addPubkey(ctx, validator.GetConsPubKey())
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
keeper.paramspace.SetParamSet(ctx, &data.Params)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
|
|
||||||
func TestCannotUnjailUnlessJailed(t *testing.T) {
|
func TestCannotUnjailUnlessJailed(t *testing.T) {
|
||||||
// initial setup
|
// initial setup
|
||||||
ctx, ck, sk, _, keeper := createTestInput(t)
|
ctx, ck, sk, _, keeper := createTestInput(t, DefaultParams())
|
||||||
slh := NewHandler(keeper)
|
slh := NewHandler(keeper)
|
||||||
amtInt := int64(100)
|
amtInt := int64(100)
|
||||||
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
|
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
|
||||||
|
@ -30,7 +30,7 @@ func TestCannotUnjailUnlessJailed(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestJailedValidatorDelegations(t *testing.T) {
|
func TestJailedValidatorDelegations(t *testing.T) {
|
||||||
ctx, _, stakeKeeper, _, slashingKeeper := createTestInput(t)
|
ctx, _, stakeKeeper, _, slashingKeeper := createTestInput(t, DefaultParams())
|
||||||
|
|
||||||
stakeParams := stakeKeeper.GetParams(ctx)
|
stakeParams := stakeKeeper.GetParams(ctx)
|
||||||
stakeParams.UnbondingTime = 0
|
stakeParams.UnbondingTime = 0
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHookOnValidatorBonded(t *testing.T) {
|
func TestHookOnValidatorBonded(t *testing.T) {
|
||||||
ctx, _, _, _, keeper := createTestInput(t)
|
ctx, _, _, _, keeper := createTestInput(t, DefaultParams())
|
||||||
addr := sdk.ConsAddress(addrs[0])
|
addr := sdk.ConsAddress(addrs[0])
|
||||||
keeper.onValidatorBonded(ctx, addr)
|
keeper.onValidatorBonded(ctx, addr)
|
||||||
period := keeper.getValidatorSlashingPeriodForHeight(ctx, addr, ctx.BlockHeight())
|
period := keeper.getValidatorSlashingPeriodForHeight(ctx, addr, ctx.BlockHeight())
|
||||||
|
@ -17,7 +17,7 @@ func TestHookOnValidatorBonded(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHookOnValidatorBeginUnbonding(t *testing.T) {
|
func TestHookOnValidatorBeginUnbonding(t *testing.T) {
|
||||||
ctx, _, _, _, keeper := createTestInput(t)
|
ctx, _, _, _, keeper := createTestInput(t, DefaultParams())
|
||||||
addr := sdk.ConsAddress(addrs[0])
|
addr := sdk.ConsAddress(addrs[0])
|
||||||
keeper.onValidatorBonded(ctx, addr)
|
keeper.onValidatorBonded(ctx, addr)
|
||||||
keeper.onValidatorBeginUnbonding(ctx, addr)
|
keeper.onValidatorBeginUnbonding(ctx, addr)
|
||||||
|
|
|
@ -19,18 +19,19 @@ type Keeper struct {
|
||||||
storeKey sdk.StoreKey
|
storeKey sdk.StoreKey
|
||||||
cdc *codec.Codec
|
cdc *codec.Codec
|
||||||
validatorSet sdk.ValidatorSet
|
validatorSet sdk.ValidatorSet
|
||||||
params params.Getter
|
paramspace params.Subspace
|
||||||
|
|
||||||
// codespace
|
// codespace
|
||||||
codespace sdk.CodespaceType
|
codespace sdk.CodespaceType
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewKeeper creates a slashing keeper
|
// 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{
|
keeper := Keeper{
|
||||||
storeKey: key,
|
storeKey: key,
|
||||||
cdc: cdc,
|
cdc: cdc,
|
||||||
validatorSet: vs,
|
validatorSet: vs,
|
||||||
params: params,
|
paramspace: paramspace.WithTypeTable(ParamTypeTable()),
|
||||||
codespace: codespace,
|
codespace: codespace,
|
||||||
}
|
}
|
||||||
return keeper
|
return keeper
|
||||||
|
|
|
@ -12,10 +12,12 @@ import (
|
||||||
|
|
||||||
// Have to change these parameters for tests
|
// Have to change these parameters for tests
|
||||||
// lest the tests take forever
|
// lest the tests take forever
|
||||||
func init() {
|
func keeperTestParams() Params {
|
||||||
defaultSignedBlocksWindow = 1000
|
params := DefaultParams()
|
||||||
defaultDowntimeUnbondDuration = 60 * 60
|
params.SignedBlocksWindow = 1000
|
||||||
defaultDoubleSignUnbondDuration = 60 * 60
|
params.DowntimeUnbondDuration = 60 * 60
|
||||||
|
params.DoubleSignUnbondDuration = 60 * 60
|
||||||
|
return params
|
||||||
}
|
}
|
||||||
|
|
||||||
// ______________________________________________________________
|
// ______________________________________________________________
|
||||||
|
@ -25,7 +27,7 @@ func init() {
|
||||||
func TestHandleDoubleSign(t *testing.T) {
|
func TestHandleDoubleSign(t *testing.T) {
|
||||||
|
|
||||||
// initial setup
|
// initial setup
|
||||||
ctx, ck, sk, _, keeper := createTestInput(t)
|
ctx, ck, sk, _, keeper := createTestInput(t, keeperTestParams())
|
||||||
// validator added pre-genesis
|
// validator added pre-genesis
|
||||||
ctx = ctx.WithBlockHeight(-1)
|
ctx = ctx.WithBlockHeight(-1)
|
||||||
amtInt := int64(100)
|
amtInt := int64(100)
|
||||||
|
@ -67,7 +69,7 @@ func TestHandleDoubleSign(t *testing.T) {
|
||||||
func TestSlashingPeriodCap(t *testing.T) {
|
func TestSlashingPeriodCap(t *testing.T) {
|
||||||
|
|
||||||
// initial setup
|
// initial setup
|
||||||
ctx, ck, sk, _, keeper := createTestInput(t)
|
ctx, ck, sk, _, keeper := createTestInput(t, DefaultParams())
|
||||||
amtInt := int64(100)
|
amtInt := int64(100)
|
||||||
operatorAddr, amt := addrs[0], sdk.NewInt(amtInt)
|
operatorAddr, amt := addrs[0], sdk.NewInt(amtInt)
|
||||||
valConsPubKey, valConsAddr := pks[0], pks[0].Address()
|
valConsPubKey, valConsAddr := pks[0], pks[0].Address()
|
||||||
|
@ -132,7 +134,7 @@ func TestSlashingPeriodCap(t *testing.T) {
|
||||||
func TestHandleAbsentValidator(t *testing.T) {
|
func TestHandleAbsentValidator(t *testing.T) {
|
||||||
|
|
||||||
// initial setup
|
// initial setup
|
||||||
ctx, ck, sk, _, keeper := createTestInput(t)
|
ctx, ck, sk, _, keeper := createTestInput(t, keeperTestParams())
|
||||||
amtInt := int64(100)
|
amtInt := int64(100)
|
||||||
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
|
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
|
||||||
sh := stake.NewHandler(sk)
|
sh := stake.NewHandler(sk)
|
||||||
|
@ -284,7 +286,7 @@ func TestHandleAbsentValidator(t *testing.T) {
|
||||||
// and that they are not immediately jailed
|
// and that they are not immediately jailed
|
||||||
func TestHandleNewValidator(t *testing.T) {
|
func TestHandleNewValidator(t *testing.T) {
|
||||||
// initial setup
|
// initial setup
|
||||||
ctx, ck, sk, _, keeper := createTestInput(t)
|
ctx, ck, sk, _, keeper := createTestInput(t, keeperTestParams())
|
||||||
addr, val, amt := addrs[0], pks[0], int64(100)
|
addr, val, amt := addrs[0], pks[0], int64(100)
|
||||||
sh := stake.NewHandler(sk)
|
sh := stake.NewHandler(sk)
|
||||||
|
|
||||||
|
@ -323,7 +325,7 @@ func TestHandleNewValidator(t *testing.T) {
|
||||||
func TestHandleAlreadyJailed(t *testing.T) {
|
func TestHandleAlreadyJailed(t *testing.T) {
|
||||||
|
|
||||||
// initial setup
|
// initial setup
|
||||||
ctx, _, sk, _, keeper := createTestInput(t)
|
ctx, _, sk, _, keeper := createTestInput(t, DefaultParams())
|
||||||
amtInt := int64(100)
|
amtInt := int64(100)
|
||||||
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
|
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
|
||||||
sh := stake.NewHandler(sk)
|
sh := stake.NewHandler(sk)
|
||||||
|
@ -371,7 +373,7 @@ func TestHandleAlreadyJailed(t *testing.T) {
|
||||||
func TestValidatorDippingInAndOut(t *testing.T) {
|
func TestValidatorDippingInAndOut(t *testing.T) {
|
||||||
|
|
||||||
// initial setup
|
// initial setup
|
||||||
ctx, _, sk, _, keeper := createTestInput(t)
|
ctx, _, sk, _, keeper := createTestInput(t, keeperTestParams())
|
||||||
params := sk.GetParams(ctx)
|
params := sk.GetParams(ctx)
|
||||||
params.MaxValidators = 1
|
params.MaxValidators = 1
|
||||||
sk.SetParams(ctx, params)
|
sk.SetParams(ctx, params)
|
||||||
|
|
|
@ -4,77 +4,119 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// nolint
|
// Default parameter namespace
|
||||||
const (
|
const (
|
||||||
MaxEvidenceAgeKey = "slashing/MaxEvidenceAge"
|
DefaultParamspace = "slashing"
|
||||||
SignedBlocksWindowKey = "slashing/SignedBlocksWindow"
|
|
||||||
MinSignedPerWindowKey = "slashing/MinSignedPerWindow"
|
|
||||||
DoubleSignUnbondDurationKey = "slashing/DoubleSignUnbondDuration"
|
|
||||||
DowntimeUnbondDurationKey = "slashing/DowntimeUnbondDuration"
|
|
||||||
SlashFractionDoubleSignKey = "slashing/SlashFractionDoubleSign"
|
|
||||||
SlashFractionDowntimeKey = "slashing/SlashFractionDowntime"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 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 - Max age for evidence - 21 days (3 weeks)
|
||||||
// MaxEvidenceAge = 60 * 60 * 24 * 7 * 3
|
// MaxEvidenceAge = 60 * 60 * 24 * 7 * 3
|
||||||
func (k Keeper) MaxEvidenceAge(ctx sdk.Context) time.Duration {
|
func (k Keeper) MaxEvidenceAge(ctx sdk.Context) (res time.Duration) {
|
||||||
return time.Duration(k.params.GetInt64WithDefault(ctx, MaxEvidenceAgeKey, defaultMaxEvidenceAge)) * time.Second
|
k.paramspace.Get(ctx, KeyMaxEvidenceAge, &res)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignedBlocksWindow - sliding window for downtime slashing
|
// SignedBlocksWindow - sliding window for downtime slashing
|
||||||
func (k Keeper) SignedBlocksWindow(ctx sdk.Context) int64 {
|
func (k Keeper) SignedBlocksWindow(ctx sdk.Context) (res int64) {
|
||||||
return k.params.GetInt64WithDefault(ctx, SignedBlocksWindowKey, defaultSignedBlocksWindow)
|
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 {
|
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)
|
signedBlocksWindow := k.SignedBlocksWindow(ctx)
|
||||||
return sdk.NewDec(signedBlocksWindow).Mul(minSignedPerWindow).RoundInt64()
|
return sdk.NewDec(signedBlocksWindow).Mul(minSignedPerWindow).RoundInt64()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Double-sign unbond duration
|
// Double-sign unbond duration
|
||||||
func (k Keeper) DoubleSignUnbondDuration(ctx sdk.Context) time.Duration {
|
func (k Keeper) DoubleSignUnbondDuration(ctx sdk.Context) (res time.Duration) {
|
||||||
return time.Duration(k.params.GetInt64WithDefault(ctx, DoubleSignUnbondDurationKey, defaultDoubleSignUnbondDuration)) * time.Second
|
k.paramspace.Get(ctx, KeyDoubleSignUnbondDuration, &res)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Downtime unbond duration
|
// Downtime unbond duration
|
||||||
func (k Keeper) DowntimeUnbondDuration(ctx sdk.Context) time.Duration {
|
func (k Keeper) DowntimeUnbondDuration(ctx sdk.Context) (res time.Duration) {
|
||||||
return time.Duration(k.params.GetInt64WithDefault(ctx, DowntimeUnbondDurationKey, defaultDowntimeUnbondDuration)) * time.Second
|
k.paramspace.Get(ctx, KeyDowntimeUnbondDuration, &res)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// SlashFractionDoubleSign - currently default 5%
|
// SlashFractionDoubleSign - currently default 5%
|
||||||
func (k Keeper) SlashFractionDoubleSign(ctx sdk.Context) sdk.Dec {
|
func (k Keeper) SlashFractionDoubleSign(ctx sdk.Context) (res sdk.Dec) {
|
||||||
return k.params.GetDecWithDefault(ctx, SlashFractionDoubleSignKey, defaultSlashFractionDoubleSign)
|
k.paramspace.Get(ctx, KeySlashFractionDoubleSign, &res)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// SlashFractionDowntime - currently default 1%
|
// SlashFractionDowntime - currently default 1%
|
||||||
func (k Keeper) SlashFractionDowntime(ctx sdk.Context) sdk.Dec {
|
func (k Keeper) SlashFractionDowntime(ctx sdk.Context) (res sdk.Dec) {
|
||||||
return k.params.GetDecWithDefault(ctx, SlashFractionDowntimeKey, defaultSlashFractionDowntime)
|
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))
|
|
||||||
)
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetSetValidatorSigningInfo(t *testing.T) {
|
func TestGetSetValidatorSigningInfo(t *testing.T) {
|
||||||
ctx, _, _, _, keeper := createTestInput(t)
|
ctx, _, _, _, keeper := createTestInput(t, DefaultParams())
|
||||||
info, found := keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(addrs[0]))
|
info, found := keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(addrs[0]))
|
||||||
require.False(t, found)
|
require.False(t, found)
|
||||||
newInfo := ValidatorSigningInfo{
|
newInfo := ValidatorSigningInfo{
|
||||||
|
@ -29,7 +29,7 @@ func TestGetSetValidatorSigningInfo(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetSetValidatorSigningBitArray(t *testing.T) {
|
func TestGetSetValidatorSigningBitArray(t *testing.T) {
|
||||||
ctx, _, _, _, keeper := createTestInput(t)
|
ctx, _, _, _, keeper := createTestInput(t, DefaultParams())
|
||||||
missed := keeper.getValidatorSigningBitArray(ctx, sdk.ConsAddress(addrs[0]), 0)
|
missed := keeper.getValidatorSigningBitArray(ctx, sdk.ConsAddress(addrs[0]), 0)
|
||||||
require.False(t, missed) // treat empty key as not missed
|
require.False(t, missed) // treat empty key as not missed
|
||||||
keeper.setValidatorSigningBitArray(ctx, sdk.ConsAddress(addrs[0]), 0, true)
|
keeper.setValidatorSigningBitArray(ctx, sdk.ConsAddress(addrs[0]), 0, true)
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetSetValidatorSlashingPeriod(t *testing.T) {
|
func TestGetSetValidatorSlashingPeriod(t *testing.T) {
|
||||||
ctx, _, _, _, keeper := createTestInput(t)
|
ctx, _, _, _, keeper := createTestInput(t, DefaultParams())
|
||||||
addr := sdk.ConsAddress(addrs[0])
|
addr := sdk.ConsAddress(addrs[0])
|
||||||
height := int64(5)
|
height := int64(5)
|
||||||
require.Panics(t, func() { keeper.getValidatorSlashingPeriodForHeight(ctx, addr, height) })
|
require.Panics(t, func() { keeper.getValidatorSlashingPeriodForHeight(ctx, addr, height) })
|
||||||
|
@ -60,7 +60,7 @@ func TestGetSetValidatorSlashingPeriod(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidatorSlashingPeriodCap(t *testing.T) {
|
func TestValidatorSlashingPeriodCap(t *testing.T) {
|
||||||
ctx, _, _, _, keeper := createTestInput(t)
|
ctx, _, _, _, keeper := createTestInput(t, DefaultParams())
|
||||||
addr := sdk.ConsAddress(addrs[0])
|
addr := sdk.ConsAddress(addrs[0])
|
||||||
height := int64(5)
|
height := int64(5)
|
||||||
newPeriod := ValidatorSlashingPeriod{
|
newPeriod := ValidatorSlashingPeriod{
|
||||||
|
|
|
@ -49,12 +49,13 @@ func createTestCodec() *codec.Codec {
|
||||||
return cdc
|
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")
|
keyAcc := sdk.NewKVStoreKey("acc")
|
||||||
keyStake := sdk.NewKVStoreKey("stake")
|
keyStake := sdk.NewKVStoreKey("stake")
|
||||||
tkeyStake := sdk.NewTransientStoreKey("transient_stake")
|
tkeyStake := sdk.NewTransientStoreKey("transient_stake")
|
||||||
keySlashing := sdk.NewKVStoreKey("slashing")
|
keySlashing := sdk.NewKVStoreKey("slashing")
|
||||||
keyParams := sdk.NewKVStoreKey("params")
|
keyParams := sdk.NewKVStoreKey("params")
|
||||||
|
tkeyParams := sdk.NewTransientStoreKey("transient_params")
|
||||||
db := dbm.NewMemDB()
|
db := dbm.NewMemDB()
|
||||||
ms := store.NewCommitMultiStore(db)
|
ms := store.NewCommitMultiStore(db)
|
||||||
ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, 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(keyStake, sdk.StoreTypeIAVL, db)
|
||||||
ms.MountStoreWithDB(keySlashing, sdk.StoreTypeIAVL, db)
|
ms.MountStoreWithDB(keySlashing, sdk.StoreTypeIAVL, db)
|
||||||
ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db)
|
ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db)
|
||||||
|
ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db)
|
||||||
err := ms.LoadLatestVersion()
|
err := ms.LoadLatestVersion()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
ctx := sdk.NewContext(ms, abci.Header{Time: time.Unix(0, 0)}, false, log.NewTMLogger(os.Stdout))
|
ctx := sdk.NewContext(ms, abci.Header{Time: time.Unix(0, 0)}, false, log.NewTMLogger(os.Stdout))
|
||||||
cdc := createTestCodec()
|
cdc := createTestCodec()
|
||||||
accountMapper := auth.NewAccountMapper(cdc, keyAcc, auth.ProtoBaseAccount)
|
accountMapper := auth.NewAccountMapper(cdc, keyAcc, auth.ProtoBaseAccount)
|
||||||
|
|
||||||
ck := bank.NewBaseKeeper(accountMapper)
|
ck := bank.NewBaseKeeper(accountMapper)
|
||||||
params := params.NewKeeper(cdc, keyParams)
|
paramsKeeper := params.NewKeeper(cdc, keyParams, tkeyParams)
|
||||||
sk := stake.NewKeeper(cdc, keyStake, tkeyStake, ck, stake.DefaultCodespace)
|
sk := stake.NewKeeper(cdc, keyStake, tkeyStake, ck, paramsKeeper.Subspace(stake.DefaultParamspace), stake.DefaultCodespace)
|
||||||
genesis := stake.DefaultGenesisState()
|
genesis := stake.DefaultGenesisState()
|
||||||
|
|
||||||
genesis.Pool.LooseTokens = sdk.NewDec(initCoins.MulRaw(int64(len(addrs))).Int64())
|
genesis.Pool.LooseTokens = sdk.NewDec(initCoins.MulRaw(int64(len(addrs))).Int64())
|
||||||
|
@ -83,9 +86,15 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, para
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
keeper := NewKeeper(cdc, keySlashing, sk, params.Getter(), DefaultCodespace)
|
paramstore := paramsKeeper.Subspace(DefaultParamspace)
|
||||||
|
keeper := NewKeeper(cdc, keySlashing, sk, paramstore, DefaultCodespace)
|
||||||
sk = sk.WithHooks(keeper.Hooks())
|
sk = sk.WithHooks(keeper.Hooks())
|
||||||
return ctx, ck, sk, params.Setter(), keeper
|
|
||||||
|
require.NotPanics(t, func() {
|
||||||
|
InitGenesis(ctx, keeper, GenesisState{defaults}, genesis)
|
||||||
|
})
|
||||||
|
|
||||||
|
return ctx, ck, sk, paramstore, keeper
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPubKey(pk string) (res crypto.PubKey) {
|
func newPubKey(pk string) (res crypto.PubKey) {
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBeginBlocker(t *testing.T) {
|
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)
|
addr, pk, amt := addrs[2], pks[2], sdk.NewInt(100)
|
||||||
|
|
||||||
// bond the validator
|
// bond the validator
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
"github.com/cosmos/cosmos-sdk/x/mock"
|
"github.com/cosmos/cosmos-sdk/x/mock"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/params"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||||
|
@ -36,15 +37,21 @@ func getMockApp(t *testing.T) (*mock.App, Keeper) {
|
||||||
RegisterCodec(mApp.Cdc)
|
RegisterCodec(mApp.Cdc)
|
||||||
|
|
||||||
keyStake := sdk.NewKVStoreKey("stake")
|
keyStake := sdk.NewKVStoreKey("stake")
|
||||||
|
|
||||||
tkeyStake := sdk.NewTransientStoreKey("transient_stake")
|
tkeyStake := sdk.NewTransientStoreKey("transient_stake")
|
||||||
|
keyParams := sdk.NewKVStoreKey("params")
|
||||||
|
tkeyParams := sdk.NewTransientStoreKey("transient_params")
|
||||||
|
|
||||||
bankKeeper := bank.NewBaseKeeper(mApp.AccountMapper)
|
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.Router().AddRoute("stake", NewHandler(keeper))
|
||||||
mApp.SetEndBlocker(getEndBlocker(keeper))
|
mApp.SetEndBlocker(getEndBlocker(keeper))
|
||||||
mApp.SetInitChainer(getInitChainer(mApp, 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
|
return mApp, keeper
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -464,15 +464,17 @@ func GetCmdQueryParams(storeName string, cdc *codec.Codec) *cobra.Command {
|
||||||
Short: "Query the current staking parameters information",
|
Short: "Query the current staking parameters information",
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
key := stake.ParamKey
|
|
||||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||||
|
bz, err := cliCtx.QueryWithData("custom/stake/"+stake.QueryParameters, nil)
|
||||||
res, err := cliCtx.QueryStore(key, storeName)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
params := types.MustUnmarshalParams(cdc, res)
|
var params stake.Params
|
||||||
|
err = cdc.UnmarshalJSON(bz, ¶ms)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
switch viper.Get(cli.OutputFlag) {
|
switch viper.Get(cli.OutputFlag) {
|
||||||
case "text":
|
case "text":
|
||||||
|
|
|
@ -35,6 +35,8 @@ func NewHandler(k keeper.Keeper) sdk.Handler {
|
||||||
func EndBlocker(ctx sdk.Context, k keeper.Keeper) (ValidatorUpdates []abci.ValidatorUpdate) {
|
func EndBlocker(ctx sdk.Context, k keeper.Keeper) (ValidatorUpdates []abci.ValidatorUpdate) {
|
||||||
endBlockerTags := sdk.EmptyTags()
|
endBlockerTags := sdk.EmptyTags()
|
||||||
|
|
||||||
|
k.UnbondAllMatureValidatorQueue(ctx)
|
||||||
|
|
||||||
matureUnbonds := k.DequeueAllMatureUnbondingQueue(ctx, ctx.BlockHeader().Time)
|
matureUnbonds := k.DequeueAllMatureUnbondingQueue(ctx, ctx.BlockHeader().Time)
|
||||||
for _, dvPair := range matureUnbonds {
|
for _, dvPair := range matureUnbonds {
|
||||||
err := k.CompleteUnbonding(ctx, dvPair.DelegatorAddr, dvPair.ValidatorAddr)
|
err := k.CompleteUnbonding(ctx, dvPair.DelegatorAddr, dvPair.ValidatorAddr)
|
||||||
|
|
|
@ -629,6 +629,56 @@ func TestJailValidator(t *testing.T) {
|
||||||
require.True(t, got.IsOK(), "expected ok, got %v", got)
|
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) {
|
func TestUnbondingPeriod(t *testing.T) {
|
||||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||||
validatorAddr := sdk.ValAddress(keep.Addrs[0])
|
validatorAddr := sdk.ValAddress(keep.Addrs[0])
|
||||||
|
|
|
@ -437,7 +437,7 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA
|
||||||
//______________________________________________________________________________________________________
|
//______________________________________________________________________________________________________
|
||||||
|
|
||||||
// get info for begin functions: MinTime and CreationHeight
|
// 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) {
|
minTime time.Time, height int64, completeNow bool) {
|
||||||
|
|
||||||
validator, found := k.GetValidator(ctx, valSrcAddr)
|
validator, found := k.GetValidator(ctx, valSrcAddr)
|
||||||
|
@ -446,11 +446,11 @@ func (k Keeper) getBeginInfo(ctx sdk.Context, params types.Params, valSrcAddr sd
|
||||||
case !found || validator.Status == sdk.Bonded:
|
case !found || validator.Status == sdk.Bonded:
|
||||||
|
|
||||||
// the longest wait - just unbonding period from now
|
// the longest wait - just unbonding period from now
|
||||||
minTime = ctx.BlockHeader().Time.Add(params.UnbondingTime)
|
minTime = ctx.BlockHeader().Time.Add(k.UnbondingTime(ctx))
|
||||||
height = ctx.BlockHeader().Height
|
height = ctx.BlockHeight()
|
||||||
return minTime, height, false
|
return minTime, height, false
|
||||||
|
|
||||||
case validator.IsUnbonded(ctx):
|
case validator.Status == sdk.Unbonded:
|
||||||
return minTime, height, true
|
return minTime, height, true
|
||||||
|
|
||||||
case validator.Status == sdk.Unbonding:
|
case validator.Status == sdk.Unbonding:
|
||||||
|
@ -474,15 +474,14 @@ func (k Keeper) BeginUnbonding(ctx sdk.Context,
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the unbonding delegation
|
// create the unbonding delegation
|
||||||
params := k.GetParams(ctx)
|
minTime, height, completeNow := k.getBeginInfo(ctx, valAddr)
|
||||||
minTime, height, completeNow := k.getBeginInfo(ctx, params, valAddr)
|
|
||||||
|
|
||||||
returnAmount, err := k.unbond(ctx, delAddr, valAddr, sharesAmount)
|
returnAmount, err := k.unbond(ctx, delAddr, valAddr, sharesAmount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.UnbondingDelegation{}, err
|
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
|
// no need to create the ubd object just complete now
|
||||||
if completeNow {
|
if completeNow {
|
||||||
|
@ -537,8 +536,7 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress,
|
||||||
return types.Redelegation{}, err
|
return types.Redelegation{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
params := k.GetParams(ctx)
|
returnCoin := sdk.Coin{k.BondDenom(ctx), returnAmount.RoundInt()}
|
||||||
returnCoin := sdk.NewCoin(params.BondDenom, returnAmount.RoundInt())
|
|
||||||
dstValidator, found := k.GetValidator(ctx, valDstAddr)
|
dstValidator, found := k.GetValidator(ctx, valDstAddr)
|
||||||
if !found {
|
if !found {
|
||||||
return types.Redelegation{}, types.ErrBadRedelegationDst(k.Codespace())
|
return types.Redelegation{}, types.ErrBadRedelegationDst(k.Codespace())
|
||||||
|
@ -549,7 +547,7 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress,
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the unbonding delegation
|
// 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
|
if completeNow { // no need to create the redelegation object
|
||||||
return types.Redelegation{MinTime: minTime}, nil
|
return types.Redelegation{MinTime: minTime}, nil
|
||||||
|
|
|
@ -374,12 +374,8 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) {
|
||||||
}
|
}
|
||||||
keeper.SetDelegation(ctx, delegation)
|
keeper.SetDelegation(ctx, delegation)
|
||||||
|
|
||||||
header := ctx.BlockHeader()
|
ctx = ctx.WithBlockHeight(10)
|
||||||
blockHeight := int64(10)
|
ctx = ctx.WithBlockTime(time.Unix(333, 0))
|
||||||
header.Height = blockHeight
|
|
||||||
blockTime := time.Unix(333, 0)
|
|
||||||
header.Time = blockTime
|
|
||||||
ctx = ctx.WithBlockHeader(header)
|
|
||||||
|
|
||||||
// unbond the all self-delegation to put validator in unbonding state
|
// unbond the all self-delegation to put validator in unbonding state
|
||||||
_, err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
|
_, 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])
|
validator, found := keeper.GetValidator(ctx, addrVals[0])
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
require.Equal(t, blockHeight, validator.UnbondingHeight)
|
require.Equal(t, ctx.BlockHeight(), validator.UnbondingHeight)
|
||||||
params := keeper.GetParams(ctx)
|
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
|
// unbond the validator
|
||||||
header = ctx.BlockHeader()
|
keeper.unbondingToUnbonded(ctx, validator)
|
||||||
blockHeight2 := int64(20)
|
|
||||||
header.Height = blockHeight2
|
|
||||||
blockTime2 := time.Unix(444, 0).Add(params.UnbondingTime)
|
|
||||||
header.Time = blockTime2
|
|
||||||
ctx = ctx.WithBlockHeader(header)
|
|
||||||
|
|
||||||
// unbond some of the other delegation's shares
|
// unbond some of the other delegation's shares
|
||||||
_, err = keeper.BeginUnbonding(ctx, addrDels[0], addrVals[0], sdk.NewDec(6))
|
_, 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)
|
validator2 = testingUpdateValidator(keeper, ctx, validator2)
|
||||||
require.Equal(t, sdk.Bonded, validator2.Status)
|
require.Equal(t, sdk.Bonded, validator2.Status)
|
||||||
|
|
||||||
header := ctx.BlockHeader()
|
ctx = ctx.WithBlockHeight(10)
|
||||||
blockHeight := int64(10)
|
ctx = ctx.WithBlockTime(time.Unix(333, 0))
|
||||||
header.Height = blockHeight
|
|
||||||
blockTime := time.Unix(333, 0)
|
|
||||||
header.Time = blockTime
|
|
||||||
ctx = ctx.WithBlockHeader(header)
|
|
||||||
|
|
||||||
// unbond the all self-delegation to put validator in unbonding state
|
// unbond the all self-delegation to put validator in unbonding state
|
||||||
_, err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
|
_, 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])
|
validator, found := keeper.GetValidator(ctx, addrVals[0])
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
require.Equal(t, blockHeight, validator.UnbondingHeight)
|
require.Equal(t, ctx.BlockHeight(), validator.UnbondingHeight)
|
||||||
params := keeper.GetParams(ctx)
|
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
|
// unbond the validator
|
||||||
header = ctx.BlockHeader()
|
keeper.unbondingToUnbonded(ctx, validator)
|
||||||
blockHeight2 := int64(20)
|
|
||||||
header.Height = blockHeight2
|
|
||||||
blockTime2 := time.Unix(444, 0).Add(params.UnbondingTime)
|
|
||||||
header.Time = blockTime2
|
|
||||||
ctx = ctx.WithBlockHeader(header)
|
|
||||||
|
|
||||||
// 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))
|
_, err = keeper.BeginRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1], sdk.NewDec(6))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// no ubd should have been found, coins should have been returned direcly to account
|
// no red should have been found
|
||||||
ubd, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
|
red, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
|
||||||
require.False(t, found, "%v", ubd)
|
require.False(t, found, "%v", red)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/params"
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -15,17 +16,19 @@ type Keeper struct {
|
||||||
cdc *codec.Codec
|
cdc *codec.Codec
|
||||||
bankKeeper bank.Keeper
|
bankKeeper bank.Keeper
|
||||||
hooks sdk.StakingHooks
|
hooks sdk.StakingHooks
|
||||||
|
paramstore params.Subspace
|
||||||
|
|
||||||
// codespace
|
// codespace
|
||||||
codespace sdk.CodespaceType
|
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{
|
keeper := Keeper{
|
||||||
storeKey: key,
|
storeKey: key,
|
||||||
storeTKey: tkey,
|
storeTKey: tkey,
|
||||||
cdc: cdc,
|
cdc: cdc,
|
||||||
bankKeeper: ck,
|
bankKeeper: ck,
|
||||||
|
paramstore: paramstore.WithTypeTable(ParamTypeTable()),
|
||||||
hooks: nil,
|
hooks: nil,
|
||||||
codespace: codespace,
|
codespace: codespace,
|
||||||
}
|
}
|
||||||
|
@ -48,29 +51,6 @@ func (k Keeper) Codespace() sdk.CodespaceType {
|
||||||
return k.codespace
|
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, ¶ms)
|
|
||||||
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
|
// load/save the pool
|
||||||
|
|
|
@ -13,7 +13,8 @@ import (
|
||||||
//nolint
|
//nolint
|
||||||
var (
|
var (
|
||||||
// Keys for store prefixes
|
// 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
|
PoolKey = []byte{0x01} // key for the staking pools
|
||||||
ValidatorsKey = []byte{0x02} // prefix for each key to a validator
|
ValidatorsKey = []byte{0x02} // prefix for each key to a validator
|
||||||
ValidatorsByConsAddrKey = []byte{0x03} // prefix for each key to a validator index, by pubkey
|
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
|
RedelegationByValDstIndexKey = []byte{0x0C} // prefix for each key for an redelegation, by destination validator operator
|
||||||
UnbondingQueueKey = []byte{0x0D} // prefix for the timestamps in unbonding queue
|
UnbondingQueueKey = []byte{0x0D} // prefix for the timestamps in unbonding queue
|
||||||
RedelegationQueueKey = []byte{0x0E} // prefix for the timestamps in redelegations 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
|
const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch
|
||||||
|
@ -85,6 +87,12 @@ func getValidatorPowerRank(validator types.Validator) []byte {
|
||||||
return key
|
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
|
// gets the key for delegator bond with validator
|
||||||
|
|
|
@ -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, ¶ms)
|
||||||
|
}
|
|
@ -46,7 +46,7 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh
|
||||||
}
|
}
|
||||||
|
|
||||||
// should not be slashing unbonded
|
// 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()))
|
panic(fmt.Sprintf("should not be slashing unbonded validator: %s", validator.GetOperator()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/params"
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
"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")
|
keyStake := sdk.NewKVStoreKey("stake")
|
||||||
tkeyStake := sdk.NewTransientStoreKey("transient_stake")
|
tkeyStake := sdk.NewTransientStoreKey("transient_stake")
|
||||||
keyAcc := sdk.NewKVStoreKey("acc")
|
keyAcc := sdk.NewKVStoreKey("acc")
|
||||||
|
keyParams := sdk.NewKVStoreKey("params")
|
||||||
|
tkeyParams := sdk.NewTransientStoreKey("transient_params")
|
||||||
|
|
||||||
db := dbm.NewMemDB()
|
db := dbm.NewMemDB()
|
||||||
ms := store.NewCommitMultiStore(db)
|
ms := store.NewCommitMultiStore(db)
|
||||||
ms.MountStoreWithDB(tkeyStake, sdk.StoreTypeTransient, nil)
|
ms.MountStoreWithDB(tkeyStake, sdk.StoreTypeTransient, nil)
|
||||||
ms.MountStoreWithDB(keyStake, sdk.StoreTypeIAVL, db)
|
ms.MountStoreWithDB(keyStake, sdk.StoreTypeIAVL, db)
|
||||||
ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db)
|
ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db)
|
||||||
|
ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db)
|
||||||
|
ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db)
|
||||||
err := ms.LoadLatestVersion()
|
err := ms.LoadLatestVersion()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
@ -106,8 +111,11 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context
|
||||||
keyAcc, // target store
|
keyAcc, // target store
|
||||||
auth.ProtoBaseAccount, // prototype
|
auth.ProtoBaseAccount, // prototype
|
||||||
)
|
)
|
||||||
|
|
||||||
ck := bank.NewBaseKeeper(accountMapper)
|
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.SetPool(ctx, types.InitialPool())
|
||||||
keeper.SetParams(ctx, types.DefaultParams())
|
keeper.SetParams(ctx, types.DefaultParams())
|
||||||
keeper.InitIntraTxCounter(ctx)
|
keeper.InitIntraTxCounter(ctx)
|
||||||
|
@ -116,7 +124,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context
|
||||||
for _, addr := range Addrs {
|
for _, addr := range Addrs {
|
||||||
pool := keeper.GetPool(ctx)
|
pool := keeper.GetPool(ctx)
|
||||||
_, _, err := ck.AddCoins(ctx, addr, sdk.Coins{
|
_, _, err := ck.AddCoins(ctx, addr, sdk.Coins{
|
||||||
{keeper.GetParams(ctx).BondDenom, sdk.NewInt(initCoins)},
|
{keeper.BondDenom(ctx), sdk.NewInt(initCoins)},
|
||||||
})
|
})
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
pool.LooseTokens = pool.LooseTokens.Add(sdk.NewDec(initCoins))
|
pool.LooseTokens = pool.LooseTokens.Add(sdk.NewDec(initCoins))
|
||||||
|
|
|
@ -131,8 +131,9 @@ func (k Keeper) unbondedToBonded(ctx sdk.Context, validator types.Validator) typ
|
||||||
return k.bondValidator(ctx, validator)
|
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 {
|
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))
|
panic(fmt.Sprintf("bad state transition unbondingToBonded, validator: %v\n", validator))
|
||||||
}
|
}
|
||||||
return k.completeUnbondingValidator(ctx, 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)
|
k.SetValidatorByPowerIndex(ctx, validator, pool)
|
||||||
|
|
||||||
|
// Adds to unbonding validator queue
|
||||||
|
k.InsertValidatorQueue(ctx, validator)
|
||||||
|
|
||||||
// call the unbond hook if present
|
// call the unbond hook if present
|
||||||
if k.hooks != nil {
|
if k.hooks != nil {
|
||||||
k.hooks.OnValidatorBeginUnbonding(ctx, validator.ConsAddress())
|
k.hooks.OnValidatorBeginUnbonding(ctx, validator.ConsAddress())
|
||||||
|
|
|
@ -3,6 +3,7 @@ package keeper
|
||||||
import (
|
import (
|
||||||
"container/list"
|
"container/list"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake/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)
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
|
||||||
// add the actual validator power sorted store
|
// add the actual validator power sorted store
|
||||||
maxValidators := k.GetParams(ctx).MaxValidators
|
maxValidators := k.MaxValidators(ctx)
|
||||||
validators = make([]types.Validator, maxValidators)
|
validators = make([]types.Validator, maxValidators)
|
||||||
|
|
||||||
iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey)
|
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
|
// get the group of bonded validators sorted by power-rank
|
||||||
func (k Keeper) GetBondedValidatorsByPower(ctx sdk.Context) []types.Validator {
|
func (k Keeper) GetBondedValidatorsByPower(ctx sdk.Context) []types.Validator {
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
maxValidators := k.GetParams(ctx).MaxValidators
|
maxValidators := k.MaxValidators(ctx)
|
||||||
validators := make([]types.Validator, maxValidators)
|
validators := make([]types.Validator, maxValidators)
|
||||||
|
|
||||||
iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey)
|
iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey)
|
||||||
|
@ -281,3 +282,69 @@ func (k Keeper) GetBondedValidatorsByPower(ctx sdk.Context) []types.Validator {
|
||||||
}
|
}
|
||||||
return validators[:i] // trim
|
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(), ×lice)
|
||||||
|
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(), ×lice)
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
"github.com/cosmos/cosmos-sdk/x/mock"
|
"github.com/cosmos/cosmos-sdk/x/mock"
|
||||||
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
|
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/params"
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,7 +24,11 @@ func TestStakeWithRandomMessages(t *testing.T) {
|
||||||
bankKeeper := bank.NewBaseKeeper(mapper)
|
bankKeeper := bank.NewBaseKeeper(mapper)
|
||||||
stakeKey := sdk.NewKVStoreKey("stake")
|
stakeKey := sdk.NewKVStoreKey("stake")
|
||||||
stakeTKey := sdk.NewTransientStoreKey("transient_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.Router().AddRoute("stake", stake.NewHandler(stakeKeeper))
|
||||||
mapp.SetEndBlocker(func(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
|
mapp.SetEndBlocker(func(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
|
||||||
validatorUpdates := stake.EndBlocker(ctx, stakeKeeper)
|
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 {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,6 @@ var (
|
||||||
GetValidatorsByPowerIndexKey = keeper.GetValidatorsByPowerIndexKey
|
GetValidatorsByPowerIndexKey = keeper.GetValidatorsByPowerIndexKey
|
||||||
GetDelegationKey = keeper.GetDelegationKey
|
GetDelegationKey = keeper.GetDelegationKey
|
||||||
GetDelegationsKey = keeper.GetDelegationsKey
|
GetDelegationsKey = keeper.GetDelegationsKey
|
||||||
ParamKey = keeper.ParamKey
|
|
||||||
PoolKey = keeper.PoolKey
|
PoolKey = keeper.PoolKey
|
||||||
ValidatorsKey = keeper.ValidatorsKey
|
ValidatorsKey = keeper.ValidatorsKey
|
||||||
ValidatorsByConsAddrKey = keeper.ValidatorsByConsAddrKey
|
ValidatorsByConsAddrKey = keeper.ValidatorsByConsAddrKey
|
||||||
|
@ -58,6 +57,14 @@ var (
|
||||||
GetREDsToValDstIndexKey = keeper.GetREDsToValDstIndexKey
|
GetREDsToValDstIndexKey = keeper.GetREDsToValDstIndexKey
|
||||||
GetREDsByDelToValDstIndexKey = keeper.GetREDsByDelToValDstIndexKey
|
GetREDsByDelToValDstIndexKey = keeper.GetREDsByDelToValDstIndexKey
|
||||||
|
|
||||||
|
DefaultParamspace = keeper.DefaultParamspace
|
||||||
|
KeyInflationRateChange = types.KeyInflationRateChange
|
||||||
|
KeyInflationMax = types.KeyInflationMax
|
||||||
|
KeyGoalBonded = types.KeyGoalBonded
|
||||||
|
KeyUnbondingTime = types.KeyUnbondingTime
|
||||||
|
KeyMaxValidators = types.KeyMaxValidators
|
||||||
|
KeyBondDenom = types.KeyBondDenom
|
||||||
|
|
||||||
DefaultParams = types.DefaultParams
|
DefaultParams = types.DefaultParams
|
||||||
InitialPool = types.InitialPool
|
InitialPool = types.InitialPool
|
||||||
NewValidator = types.NewValidator
|
NewValidator = types.NewValidator
|
||||||
|
@ -79,6 +86,18 @@ var (
|
||||||
NewQuerier = querier.NewQuerier
|
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 (
|
const (
|
||||||
DefaultCodespace = types.DefaultCodespace
|
DefaultCodespace = types.DefaultCodespace
|
||||||
CodeInvalidValidator = types.CodeInvalidValidator
|
CodeInvalidValidator = types.CodeInvalidValidator
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -21,6 +22,19 @@ const (
|
||||||
ValidatorUpdateDelay int64 = 1
|
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
|
// Params defines the high level settings for staking
|
||||||
type Params struct {
|
type Params struct {
|
||||||
InflationRateChange sdk.Dec `json:"inflation_rate_change"` // maximum annual change in inflation rate
|
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
|
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.
|
// Equal returns a boolean determining if two Param types are identical.
|
||||||
func (p Params) Equal(p2 Params) bool {
|
func (p Params) Equal(p2 Params) bool {
|
||||||
bz1 := MsgCdc.MustMarshalBinary(&p)
|
bz1 := MsgCdc.MustMarshalBinary(&p)
|
||||||
|
|
|
@ -435,21 +435,6 @@ func (v Validator) BondedTokens() sdk.Dec {
|
||||||
return sdk.ZeroDec()
|
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
|
// ensure fulfills the sdk validator types
|
||||||
|
|
Loading…
Reference in New Issue