Merge branch 'develop' into cwgoes/a-random-walk-down-proof-of-stake

This commit is contained in:
Christopher Goes 2018-07-17 02:23:10 +02:00
commit a6dd96db4d
38 changed files with 7886 additions and 364 deletions

View File

@ -1,5 +1,29 @@
# Changelog
## 0.22.0
*July 16th, 2018*
BREAKING CHANGES
* [x/gov] Increase VotingPeriod, DepositPeriod, and MinDeposit
IMPROVEMENTS
* [gaiad] Default config updates:
- `timeout_commit=5000` so blocks only made every 5s
- `prof_listen_addr=localhost:6060` so profile server is on by default
- `p2p.send_rate` and `p2p.recv_rate` increases 10x (~5MB/s)
BUG FIXES
* [server] Fix to actually overwrite default tendermint config
## 0.21.1
*July 14th, 2018*
BUG FIXES
* [build] Added Ledger build support via `LEDGER_ENABLED=true|false`
* True by default except when cross-compiling
## 0.21.0
*July 13th, 2018*
@ -24,6 +48,8 @@ BUG FIXES
* [keys] \#1629 - updating password no longer asks for a new password when the first entered password was incorrect
* [lcd] importing an account would create a random account
* [server] 'gaiad init' command family now writes provided name as the moniker in `config.toml`
* [build] Added Ledger build support via `LEDGER_ENABLED=true|false`
* True by default except when cross-compiling
## 0.20.0

18
Gopkg.lock generated
View File

@ -2,7 +2,6 @@
[[projects]]
branch = "master"
digest = "1:09a7f74eb6bb3c0f14d8926610c87f569c5cff68e978d30e9a3540aeb626fdf0"
name = "github.com/bartekn/go-bip39"
packages = ["."]
@ -42,12 +41,11 @@
revision = "fdfc19097e7ac6b57035062056f5b7b4638b8898"
[[projects]]
branch = "master"
digest = "1:386de157f7d19259a7f9c81f26ce011223ce0f090353c1152ffdf730d7d10ac2"
name = "github.com/btcsuite/btcutil"
packages = ["bech32"]
pruneopts = "UT"
revision = "ab6388e0c60ae4834a1f57511e20c17b5f78be4b"
revision = "d4cc87b860166d00d6b5b9e0d3b3d71d6088d4d4"
[[projects]]
digest = "1:a2c1d0e43bd3baaa071d1b9ed72c27d78169b2b269f71c105ac4ba34b1be4a39"
@ -58,7 +56,6 @@
version = "v1.1.0"
[[projects]]
branch = "master"
digest = "1:c7644c73a3d23741fdba8a99b1464e021a224b7e205be497271a8003a15ca41b"
name = "github.com/ebuchman/fail-test"
packages = ["."]
@ -265,7 +262,6 @@
version = "v1.0.0"
[[projects]]
branch = "master"
digest = "1:98225904b7abff96c052b669b25788f18225a36673fba022fb93514bb9a2a64e"
name = "github.com/prometheus/client_golang"
packages = [
@ -309,7 +305,6 @@
revision = "ae68e2d4c00fed4943b5f6698d504a5fe083da8a"
[[projects]]
branch = "master"
digest = "1:c4556a44e350b50a490544d9b06e9fba9c286c21d6c0e47f54f3a9214597298c"
name = "github.com/rcrowley/go-metrics"
packages = ["."]
@ -428,7 +423,7 @@
version = "v0.9.2"
[[projects]]
digest = "1:2511fa7bc2725251a1a48a923c8f01cd41de29b00a21224092d448a9e4627c21"
digest = "1:5f41a7655812fa5901c71735dc8845f33184e94a2020c770f60a1a80ed228cb3"
name = "github.com/tendermint/tendermint"
packages = [
"abci/client",
@ -486,15 +481,15 @@
"version",
]
pruneopts = "UT"
revision = "5ff65274b84ea905787a48512cc3124385bddf2f"
version = "v0.22.2"
revision = "c64a3c74c870d725ba1356f75b4afadf0928c297"
version = "v0.22.4"
[[projects]]
digest = "1:9d2f5bccd058537986ef2862b8c6daff855f293d924ae8ebc18974143ae9191e"
digest = "1:5bd938386bd1f61a581bf8cd6ff2b7b2f79c542929176db4ceb44965440dae07"
name = "github.com/zondax/ledger-goclient"
packages = ["."]
pruneopts = "UT"
revision = "065cbf938a16f20335c40cfe180f9cd4955c6a5a"
revision = "39ba4728c137c75718a21f9b4b3280fa31b9139b"
[[projects]]
branch = "master"
@ -517,7 +512,6 @@
revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602"
[[projects]]
branch = "master"
digest = "1:04dda8391c3e2397daf254ac68003f30141c069b228d06baec8324a5f81dc1e9"
name = "golang.org/x/net"
packages = [

View File

@ -10,11 +10,6 @@
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
@ -62,15 +57,15 @@
[[override]]
name = "github.com/tendermint/tendermint"
version = "=0.22.2"
version = "=0.22.4"
[[constraint]]
name = "github.com/bartekn/go-bip39"
branch = "master"
revision = "a05967ea095d81c8fe4833776774cfaff8e5036c"
[[constraint]]
name = "github.com/zondax/ledger-goclient"
revision = "065cbf938a16f20335c40cfe180f9cd4955c6a5a"
revision = "39ba4728c137c75718a21f9b4b3280fa31b9139b"
[prune]
go-tests = true

View File

@ -2,8 +2,10 @@ PACKAGES=$(shell go list ./... | grep -v '/vendor/')
PACKAGES_NOCLITEST=$(shell go list ./... | grep -v '/vendor/' | grep -v '/simulation' | grep -v github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test)
PACKAGES_SIMTEST=$(shell go list ./... | grep -v '/vendor/' | grep '/simulation')
COMMIT_HASH := $(shell git rev-parse --short HEAD)
BUILD_FLAGS = -tags netgo -ldflags "-X github.com/cosmos/cosmos-sdk/version.GitCommit=${COMMIT_HASH}"
BUILD_TAGS = netgo ledger
BUILD_FLAGS = -tags "${BUILD_TAGS}" -ldflags "-X github.com/cosmos/cosmos-sdk/version.GitCommit=${COMMIT_HASH}"
GCC := $(shell command -v gcc 2> /dev/null)
LEDGER_ENABLED ?= true
all: get_tools get_vendor_deps install install_examples test_lint test test_sim
########################################
@ -12,10 +14,19 @@ all: get_tools get_vendor_deps install install_examples test_lint test test_sim
ci: get_tools get_vendor_deps install test_cover test_lint test
########################################
### Build
### Build/Install
# This can be unified later, here for easy demos
build:
check-ledger:
ifeq ($(LEDGER_ENABLED),true)
ifndef GCC
$(error "gcc not installed for ledger support, please install")
endif
else
TMP_BUILD_TAGS := $(BUILD_TAGS)
BUILD_TAGS = $(filter-out ledger, $(TMP_BUILD_TAGS))
endif
build: check-ledger
ifeq ($(OS),Windows_NT)
go build $(BUILD_FLAGS) -o build/gaiad.exe ./cmd/gaia/cmd/gaiad
go build $(BUILD_FLAGS) -o build/gaiacli.exe ./cmd/gaia/cmd/gaiacli
@ -24,6 +35,9 @@ else
go build $(BUILD_FLAGS) -o build/gaiacli ./cmd/gaia/cmd/gaiacli
endif
build-linux:
LEDGER_ENABLED=false GOOS=linux GOARCH=amd64 $(MAKE) build
build_examples:
ifeq ($(OS),Windows_NT)
go build $(BUILD_FLAGS) -o build/basecoind.exe ./examples/basecoin/cmd/basecoind
@ -37,7 +51,7 @@ else
go build $(BUILD_FLAGS) -o build/democli ./examples/democoin/cmd/democli
endif
install:
install: check-ledger
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiad
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiacli
@ -109,6 +123,8 @@ test_lint:
gometalinter.v2 --config=tools/gometalinter.json ./...
!(gometalinter.v2 --disable-all --enable='errcheck' --vendor ./... | grep -v "client/")
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -d -s
dep status >> /dev/null
!(grep -n branch Gopkg.toml)
format:
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -w -s
@ -145,10 +161,6 @@ devdoc_update:
########################################
### Local validator nodes using docker and docker-compose
# Build linux binary
build-linux:
GOOS=linux GOARCH=amd64 $(MAKE) build
build-docker-gaiadnode:
$(MAKE) -C networks/local
@ -185,4 +197,8 @@ remotenet-status:
# 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: build build_examples install install_examples install_debug dist check_tools get_tools get_vendor_deps draw_deps test test_cli test_unit test_cover test_sim test_lint benchmark devdoc_init devdoc devdoc_save devdoc_update build-linux build-docker-gaiadnode localnet-start localnet-stop remotenet-start remotenet-stop remotenet-status format
.PHONY: build build_examples install install_examples install_debug dist \
check_tools get_tools get_vendor_deps draw_deps test test_cli test_unit \
test_cover test_lint benchmark devdoc_init devdoc devdoc_save devdoc_update \
build-linux build-docker-gaiadnode localnet-start localnet-stop remotenet-start \
remotenet-stop remotenet-status format check-ledger test_sim

1008
client/lcd/lcd_test.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -151,7 +151,7 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
appState, err := wire.MarshalJSONIndent(cdc, genesisState)
require.NoError(t, err)
genDoc.AppStateJSON = appState
genDoc.AppState = appState
// LCD listen address
var listenAddr string

View File

@ -18,6 +18,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/ibc"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/stake"
)
@ -45,6 +46,7 @@ type GaiaApp struct {
keySlashing *sdk.KVStoreKey
keyGov *sdk.KVStoreKey
keyFeeCollection *sdk.KVStoreKey
keyParams *sdk.KVStoreKey
// Manage getting and setting accounts
accountMapper auth.AccountMapper
@ -54,6 +56,7 @@ type GaiaApp struct {
stakeKeeper stake.Keeper
slashingKeeper slashing.Keeper
govKeeper gov.Keeper
paramsKeeper params.Keeper
}
// NewGaiaApp returns a reference to an initialized GaiaApp.
@ -73,6 +76,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
keySlashing: sdk.NewKVStoreKey("slashing"),
keyGov: sdk.NewKVStoreKey("gov"),
keyFeeCollection: sdk.NewKVStoreKey("fee"),
keyParams: sdk.NewKVStoreKey("params"),
}
// define the accountMapper
@ -85,10 +89,11 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
// add handlers
app.coinKeeper = bank.NewKeeper(app.accountMapper)
app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace))
app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams)
app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.coinKeeper, app.RegisterCodespace(stake.DefaultCodespace))
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.RegisterCodespace(slashing.DefaultCodespace))
app.govKeeper = gov.NewKeeper(app.cdc, app.keyGov, app.coinKeeper, app.stakeKeeper, app.RegisterCodespace(gov.DefaultCodespace))
app.feeCollectionKeeper = auth.NewFeeCollectionKeeper(app.cdc, app.keyFeeCollection)
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.paramsKeeper.Getter(), app.RegisterCodespace(slashing.DefaultCodespace))
// register message routes
app.Router().
@ -103,7 +108,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
app.SetBeginBlocker(app.BeginBlocker)
app.SetEndBlocker(app.EndBlocker)
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper))
app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake, app.keySlashing, app.keyGov, app.keyFeeCollection)
app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake, app.keySlashing, app.keyGov, app.keyFeeCollection, app.keyParams)
err := app.LoadLatestVersion(app.keyMain)
if err != nil {
cmn.Exit(err.Error())

View File

@ -24,6 +24,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/ibc"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/stake"
@ -133,6 +134,7 @@ type GaiaApp struct {
keyIBC *sdk.KVStoreKey
keyStake *sdk.KVStoreKey
keySlashing *sdk.KVStoreKey
keyParams *sdk.KVStoreKey
// Manage getting and setting accounts
accountMapper auth.AccountMapper
@ -141,6 +143,7 @@ type GaiaApp struct {
ibcMapper ibc.Mapper
stakeKeeper stake.Keeper
slashingKeeper slashing.Keeper
paramsKeeper params.Keeper
}
func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseApp)) *GaiaApp {
@ -158,6 +161,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseAp
keyIBC: sdk.NewKVStoreKey("ibc"),
keyStake: sdk.NewKVStoreKey("stake"),
keySlashing: sdk.NewKVStoreKey("slashing"),
keyParams: sdk.NewKVStoreKey("params"),
}
// define the accountMapper
@ -170,8 +174,9 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseAp
// add handlers
app.coinKeeper = bank.NewKeeper(app.accountMapper)
app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace))
app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams)
app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.coinKeeper, app.RegisterCodespace(stake.DefaultCodespace))
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.RegisterCodespace(slashing.DefaultCodespace))
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.paramsKeeper.Getter(), app.RegisterCodespace(slashing.DefaultCodespace))
// register message routes
app.Router().

View File

@ -1,13 +1,13 @@
# Connect to the `gaia-6002` Testnet
# Connect to the `gaia-7000` Testnet
Note: We are aware this documentation is a work in progress. We are actively
_**NOTE:**_ We are aware this documentation is a work in progress. We are actively
working to improve the tooling and the documentation to make this process as painless as
possible. In the meantime, join the [Validator Chat](https://riot.im/app/#/room/#cosmos_validators:matrix.org)
for technical support, and [open issues](https://github.com/cosmos/cosmos-sdk) if you run into any! Thanks very much for your patience and support. :)
## Setting Up a New Node
These instructions are for setting up a brand new full node from scratch. If you ran a full node on a previous testnet, please skip to [Upgrading From Previous Testnet](#upgrading-from-previous-testnet).
These instructions are for setting up a brand new full node from scratch. If you ran a full node on a previous testnet you will need to start from scratch due to some breaking changes in key format.
### Install Go
@ -29,7 +29,7 @@ Next, let's install the testnet's version of the Cosmos SDK.
mkdir -p $GOPATH/src/github.com/cosmos
cd $GOPATH/src/github.com/cosmos
git clone https://github.com/cosmos/cosmos-sdk
cd cosmos-sdk && git checkout v0.19.0
cd cosmos-sdk && git checkout v0.22.0
make get_tools && make get_vendor_deps && make install
```
@ -37,10 +37,10 @@ That will install the `gaiad` and `gaiacli` binaries. Verify that everything is
```bash
$ gaiad version
0.19.0-c6711810
0.22.0
$ gaiacli version
0.19.0-c6711810
0.22.0
```
### Node Setup
@ -48,60 +48,29 @@ $ gaiacli version
Create the required configuration files, and initialize the node:
```bash
gaiad init --name <your_custom_name>
gaiad init --name <your_custom_moniker>
```
> *NOTE:* Note that only ASCII characters are supported for the `--name`. Using Unicode renders your node unreachable.
You can also edit this `name` in the `~/.gaiad/config/config.toml` file:
You can also edit this `moniker` in the `~/.gaiad/config/config.toml` file:
```toml
# A custom human readable name for this node
moniker = "<your_custom_name>"
moniker = "<your_custom_moniker>"
```
Your full node has been initialized! Please skip to [Genesis & Seeds](#genesis--seeds).
## Upgrading From Previous Testnet
These instructions are for full nodes that have ran on previous testnets and would like to upgrade to the latest testnet.
### Reset Data
First, remove the outdated files and reset the data.
```bash
rm $HOME/.gaiad/config/addrbook.json $HOME/.gaiad/config/genesis.json
gaiad unsafe_reset_all
```
Your node is now in a pristine state while keeping the original `priv_validator.json` and `config.toml`. If you had any sentry nodes or full nodes setup before,
your node will still try to connect to them, but may fail if they haven't also
been upgraded.
**WARNING:** Make sure that every node has a unique `priv_validator.json`. Do not copy the `priv_validator.json` from an old node to multiple new nodes. Running two nodes with the same `priv_validator.json` will cause you to double sign.
### Software Upgrade
Now it is time to upgrade the software:
```bash
cd $GOPATH/src/github.com/cosmos/cosmos-sdk
git fetch --all && git checkout v0.19.0
make update_tools && make get_vendor_deps && make install
```
Your full node has been cleanly upgraded!
Your full node has been initialized!
## Genesis & Seeds
### Copy the Genesis File
Copy the testnet's `genesis.json` file and place it in `gaiad`'s config directory.
Fetch the testnet's `genesis.json` file and place it in `gaiad`'s config directory.
```bash
mkdir -p $HOME/.gaiad/config
cp -a $GOPATH/src/github.com/cosmos/cosmos-sdk/cmd/gaia/testnets/gaia-6002/genesis.json $HOME/.gaiad/config/genesis.json
curl https://gist.githubusercontent.com/cwgoes/00dfd24c104fc3d704692f04adf4fd35/raw/1d5ee526d22e48ff6717b1b514dca02f8b14a932/gaia-7000-final.json > $HOME/.gaiad/config/genesis.json
```
### Add Seed Nodes
@ -110,7 +79,7 @@ Your node needs to know how to find peers. You'll need to add healthy seed nodes
```toml
# Comma separated list of seed nodes to connect to
seeds = "38aa9bec3998f12ae9088b21a2d910d19d565c27@gaia-6002.coinculture.net:46656,1e124dd15bd9955a7ea844ab003b1b47f0998b70@seed.cosmos.cryptium.ch:46656"
seeds = "718145d422a823fd2a4e1e36e91b92bb0c4ddf8e@gaia-7000.coinculture.net:26656,5922bf29b48a18c2300b85cc53f424fce23927ab@67.207.73.206:26656,7c8b8fd03577cd4817f5be1f03d506f879df98d8@gaia-7000-seed1.interblock.io:26656,a28737ff02391a6e00a1d3b79befd57e68e8264c@gaia-7000-seed2.interblock.io:26656,987ffd26640cd03d08ed7e53b24dfaa7956e612d@gaia-7000-seed3.interblock.io:26656"
```
If those seeds aren't working, you can find more seeds and persistent peers on the [Cosmos Explorer](https://explorecosmos.network/nodes). Open the the `Full Nodes` pane and select nodes that do not have private (`10.x.x.x`) or [local IP addresses](https://en.wikipedia.org/wiki/Private_network). The `Persistent Peer` field contains the connection string. For best results use 4-6.
@ -183,7 +152,7 @@ View the validator pubkey for your node by typing:
gaiad tendermint show_validator
```
**WARNING:** We strongly recommend NOT using the same passphrase for multiple keys. The Tendermint team and the Interchain Foundation will not be responsible for the loss of funds.
**WARNING:** We strongly recommend NOT using the same passphrase for multiple keys. The Tendermint team and the Interchain Foundation will not be responsible for the loss of funds. This is not as important on the testnets, but is good security practice and should be followed.
## Fund your account
@ -199,7 +168,7 @@ gaiacli account <account_cosmosaccaddr>
## Run a Validator Node
[Validators](https://cosmos.network/validators) are responsible for committing new blocks to the blockchain through voting. A validator's stake is slashed if they become unavailable, double sign a transaction, or don't cast their votes. If you only want to run a full node, a VM in the cloud is fine. However, if you are want to become a validator for the Hub's `mainnet`, you should research hardened setups. Please read [Sentry Node Architecture](https://github.com/cosmos/cosmos/blob/master/VALIDATORS_FAQ.md#how-can-validators-protect-themselves-from-denial-of-service-attacks) to protect your node from DDOS and ensure high-availability. Also see the [technical requirements](https://github.com/cosmos/cosmos/blob/master/VALIDATORS_FAQ.md#technical-requirements)). There's also more info on our [website](https://cosmos.network/validators).
[Validators](https://cosmos.network/validators) are responsible for committing new blocks to the blockchain through voting. A validator's stake is slashed if they become unavailable, double sign a transaction, or don't cast their votes. If you only want to run a full node, a VM in the cloud is fine. However, if you are want to become a validator for the Hub's `mainnet`, you should research hardened setups. Please read [Sentry Node Architecture](https://forum.cosmos.network/t/sentry-node-architecture-overview/454) to protect your node from DDOS and ensure high-availability. Also see the [technical requirements](https://github.com/cosmos/cosmos/blob/master/VALIDATORS_FAQ.md#technical-requirements)). There's also more info on our [website](https://cosmos.network/validators).
### Create Your Validator
@ -219,7 +188,7 @@ gaiacli stake create-validator \
--pubkey=$(gaiad tendermint show_validator) \
--address-validator=<account_cosmosaccaddr>
--moniker="choose a moniker" \
--chain-id=gaia-6002 \
--chain-id=gaia-7000 \
--from=<key_name>
```
@ -236,7 +205,7 @@ gaiacli stake edit-validator
--website="https://cosmos.network" \
--keybase-sig="6A0D65E29A4CBC8E"
--details="To infinity and beyond!"
--chain-id=gaia-6002 \
--chain-id=gaia-7000 \
--from=<key_name>
```
@ -246,7 +215,7 @@ View the validator's information with this command:
```bash
gaiacli stake validator \
--address-validator=<account_cosmosaccaddr> \
--chain-id=gaia-6002
--chain-id=gaia-7000
```
Your validator is active if the following command returns anything:
@ -261,7 +230,7 @@ You should also be able to see your validator on the [Explorer](https://explorec
### Problem #1: My validator has `voting_power: 0`
Your validator has become auto-unbonded. In `gaia-6002`, we unbond validators if they do not vote on `50` of the last `100` blocks. Since blocks are proposed every ~2 seconds, a validator unresponsive for ~100 seconds will become unbonded. This usually happens when your `gaiad` process crashes.
Your validator has become auto-unbonded. In `gaia-7000`, we unbond validators if they do not vote on `50` of the last `100` blocks. Since blocks are proposed every ~2 seconds, a validator unresponsive for ~100 seconds will become unbonded. This usually happens when your `gaiad` process crashes.
Here's how you can return the voting power back to your validator. First, if `gaiad` is not running, start it up again:
@ -272,7 +241,7 @@ gaiad start
Wait for your full node to catch up to the latest block. Next, run the following command. Note that `<cosmosaccaddr>` is the address of your validator account, and `<name>` is the name of the validator account. You can find this info by running `gaiacli keys list`.
```bash
gaiacli stake unrevoke <cosmosaccaddr> --chain-id=gaia-6002 --from=<name>
gaiacli stake unrevoke <cosmosaccaddr> --chain-id=gaia-7000 --from=<name>
```
**WARNING:** If you don't wait for `gaiad` to sync before running `unrevoke`, you will receive an error message telling you your validator is still jailed.
@ -322,7 +291,7 @@ gaiacli stake delegate \
--address-delegator=<account_cosmosaccaddr> \
--address-validator=<validator_cosmosaccaddr> \
--from=<key_name> \
--chain-id=gaia-6002
--chain-id=gaia-7000
```
While tokens are bonded, they are pooled with all the other bonded tokens in the network. Validators and delegators obtain a percentage of shares that equal their stake in this pool.
@ -339,7 +308,7 @@ gaiacli stake unbond \
--address-validator=<validator_cosmosaccaddr> \
--shares=MAX \
--from=<key_name> \
--chain-id=gaia-6002
--chain-id=gaia-7000
```
You can check your balance and your stake delegation to see that the unbonding went through successfully.
@ -350,7 +319,7 @@ gaiacli account <account_cosmosaccaddr>
gaiacli stake delegation \
--address-delegator=<account_cosmosaccaddr> \
--address-validator=<validator_cosmosaccaddr> \
--chain-id=gaia-6002
--chain-id=gaia-7000
```
## Governance
@ -444,7 +413,7 @@ gaiacli gov query-vote \
```bash
gaiacli send \
--amount=10faucetToken \
--chain-id=gaia-6002 \
--chain-id=gaia-7000 \
--from=<key_name> \
--to=<destination_cosmosaccaddr>
```

File diff suppressed because it is too large Load Diff

View File

@ -6,13 +6,12 @@ import (
"os"
"strings"
"github.com/pkg/errors"
tcrypto "github.com/tendermint/tendermint/crypto"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/cosmos/cosmos-sdk/crypto"
"github.com/cosmos/cosmos-sdk/crypto/keys/bip39"
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
"github.com/pkg/errors"
tmcrypto "github.com/tendermint/tendermint/crypto"
dbm "github.com/tendermint/tendermint/libs/db"
)
var _ Keybase = dbKeybase{}
@ -43,10 +42,12 @@ const (
)
var (
// ErrUnsupportedSigningAlgo is raised when the caller tries to use a different signing scheme than secp256k1.
// ErrUnsupportedSigningAlgo is raised when the caller tries to use a
// different signing scheme than secp256k1.
ErrUnsupportedSigningAlgo = errors.New("unsupported signing algo: only secp256k1 is supported")
// ErrUnsupportedLanguage is raised when the caller tries to use a different language than english for creating
// a mnemonic sentence.
// ErrUnsupportedLanguage is raised when the caller tries to use a
// different language than english for creating a mnemonic sentence.
ErrUnsupportedLanguage = errors.New("unsupported language: only english is supported")
)
@ -147,7 +148,7 @@ func (kb dbKeybase) CreateLedger(name string, path crypto.DerivationPath, algo S
// CreateOffline creates a new reference to an offline keypair
// It returns the created key info
func (kb dbKeybase) CreateOffline(name string, pub tcrypto.PubKey) (Info, error) {
func (kb dbKeybase) CreateOffline(name string, pub tmcrypto.PubKey) (Info, error) {
return kb.writeOfflineKey(pub, name), nil
}
@ -162,9 +163,9 @@ func (kb *dbKeybase) persistDerivedKey(seed []byte, passwd, name, fullHdPath str
// if we have a password, use it to encrypt the private key and store it
// else store the public key only
if passwd != "" {
info = kb.writeLocalKey(tcrypto.PrivKeySecp256k1(derivedPriv), name, passwd)
info = kb.writeLocalKey(tmcrypto.PrivKeySecp256k1(derivedPriv), name, passwd)
} else {
pubk := tcrypto.PrivKeySecp256k1(derivedPriv).PubKey()
pubk := tmcrypto.PrivKeySecp256k1(derivedPriv).PubKey()
info = kb.writeOfflineKey(pubk, name)
}
return
@ -196,12 +197,12 @@ func (kb dbKeybase) Get(name string) (Info, error) {
// Sign signs the msg with the named key.
// It returns an error if the key doesn't exist or the decryption fails.
func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig tcrypto.Signature, pub tcrypto.PubKey, err error) {
func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig tmcrypto.Signature, pub tmcrypto.PubKey, err error) {
info, err := kb.Get(name)
if err != nil {
return
}
var priv tcrypto.PrivKey
var priv tmcrypto.PrivKey
switch info.(type) {
case localInfo:
linfo := info.(localInfo)
@ -240,12 +241,12 @@ func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig tcrypto.Signa
return sig, pub, nil
}
func (kb dbKeybase) ExportPrivateKeyObject(name string, passphrase string) (tcrypto.PrivKey, error) {
func (kb dbKeybase) ExportPrivateKeyObject(name string, passphrase string) (tmcrypto.PrivKey, error) {
info, err := kb.Get(name)
if err != nil {
return nil, err
}
var priv tcrypto.PrivKey
var priv tmcrypto.PrivKey
switch info.(type) {
case localInfo:
linfo := info.(localInfo)
@ -313,7 +314,7 @@ func (kb dbKeybase) ImportPubKey(name string, armor string) (err error) {
if err != nil {
return
}
pubKey, err := tcrypto.PubKeyFromBytes(pubBytes)
pubKey, err := tmcrypto.PubKeyFromBytes(pubBytes)
if err != nil {
return
}
@ -380,7 +381,7 @@ func (kb dbKeybase) Update(name, oldpass string, getNewpass func() (string, erro
}
}
func (kb dbKeybase) writeLocalKey(priv tcrypto.PrivKey, name, passphrase string) Info {
func (kb dbKeybase) writeLocalKey(priv tmcrypto.PrivKey, name, passphrase string) Info {
// encrypt private key using passphrase
privArmor := encryptArmorPrivKey(priv, passphrase)
// make Info
@ -390,13 +391,13 @@ func (kb dbKeybase) writeLocalKey(priv tcrypto.PrivKey, name, passphrase string)
return info
}
func (kb dbKeybase) writeLedgerKey(pub tcrypto.PubKey, path crypto.DerivationPath, name string) Info {
func (kb dbKeybase) writeLedgerKey(pub tmcrypto.PubKey, path crypto.DerivationPath, name string) Info {
info := newLedgerInfo(name, pub, path)
kb.writeInfo(info, name)
return info
}
func (kb dbKeybase) writeOfflineKey(pub tcrypto.PubKey, name string) Info {
func (kb dbKeybase) writeOfflineKey(pub tmcrypto.PubKey, name string) Info {
info := newOfflineInfo(name, pub)
kb.writeInfo(info, name)
return info

18
crypto/ledger.go Normal file
View File

@ -0,0 +1,18 @@
// +build cgo,ledger
package crypto
import (
ledger "github.com/zondax/ledger-goclient"
)
// If ledger support (build tag) has been enabled, automically attempt to load
// and set the ledger device, ledgerDevice, if it has not already been set.
func init() {
device, err := ledger.FindLedger()
if err != nil {
ledgerDeviceErr = err
} else {
ledgerDevice = device
}
}

View File

@ -1,19 +0,0 @@
package crypto
import (
ledger "github.com/zondax/ledger-goclient"
)
var device *ledger.Ledger
// Ledger derivation path
type DerivationPath = []uint32
// getLedger gets a copy of the device, and caches it
func getLedger() (*ledger.Ledger, error) {
var err error
if device == nil {
device, err = ledger.FindLedger()
}
return device, err
}

View File

@ -1,126 +1,162 @@
package crypto
import (
"errors"
"fmt"
secp256k1 "github.com/btcsuite/btcd/btcec"
ledger "github.com/zondax/ledger-goclient"
tcrypto "github.com/tendermint/tendermint/crypto"
tmcrypto "github.com/tendermint/tendermint/crypto"
)
func pubkeyLedgerSecp256k1(device *ledger.Ledger, path DerivationPath) (pub tcrypto.PubKey, err error) {
key, err := device.GetPublicKeySECP256K1(path)
if err != nil {
return nil, fmt.Errorf("error fetching public key: %v", err)
var (
ledgerDevice LedgerSECP256K1
ledgerDeviceErr error
// ErrMissingLedgerDevice is used to reflect that a ledger device load has
// not been attempted.
ErrMissingLedgerDevice = errors.New("missing ledger device")
)
type (
// DerivationPath represents a Ledger derivation path.
DerivationPath []uint32
// LedgerSECP256K1 reflects an interface a Ledger API must implement for
// the SECP256K1 scheme.
LedgerSECP256K1 interface {
GetPublicKeySECP256K1([]uint32) ([]byte, error)
SignSECP256K1([]uint32, []byte) ([]byte, error)
}
var p tcrypto.PubKeySecp256k1
// Reserialize in the 33-byte compressed format
cmp, err := secp256k1.ParsePubKey(key[:], secp256k1.S256())
copy(p[:], cmp.SerializeCompressed())
pub = p
return
}
func signLedgerSecp256k1(device *ledger.Ledger, path DerivationPath, msg []byte) (sig tcrypto.Signature, err error) {
bsig, err := device.SignSECP256K1(path, msg)
if err != nil {
return sig, err
// PrivKeyLedgerSecp256k1 implements PrivKey, calling the ledger nano we
// cache the PubKey from the first call to use it later.
PrivKeyLedgerSecp256k1 struct {
// CachedPubKey should be private, but we want to encode it via
// go-amino so we can view the address later, even without having the
// ledger attached.
CachedPubKey tmcrypto.PubKey
Path DerivationPath
ledger LedgerSECP256K1
}
sig = tcrypto.SignatureSecp256k1FromBytes(bsig)
return
}
)
// PrivKeyLedgerSecp256k1 implements PrivKey, calling the ledger nano
// we cache the PubKey from the first call to use it later
type PrivKeyLedgerSecp256k1 struct {
// PubKey should be private, but we want to encode it via go-amino
// so we can view the address later, even without having the ledger
// attached
CachedPubKey tcrypto.PubKey
Path DerivationPath
}
// NewPrivKeyLedgerSecp256k1 will generate a new key and store the public key
// for later use.
//
// CONTRACT: The ledger device, ledgerDevice, must be loaded and set prior to
// any creation of a PrivKeyLedgerSecp256k1.
func NewPrivKeyLedgerSecp256k1(path DerivationPath) (tmcrypto.PrivKey, error) {
if ledgerDevice == nil {
err := ErrMissingLedgerDevice
if ledgerDeviceErr != nil {
err = ledgerDeviceErr
}
return nil, fmt.Errorf("failed to create PrivKeyLedgerSecp256k1: %v", err)
}
pkl := &PrivKeyLedgerSecp256k1{Path: path, ledger: ledgerDevice}
// NewPrivKeyLedgerSecp256k1 will generate a new key and store the
// public key for later use.
func NewPrivKeyLedgerSecp256k1(path DerivationPath) (tcrypto.PrivKey, error) {
var pk PrivKeyLedgerSecp256k1
pk.Path = path
// cache the pubkey for later use
pubKey, err := pk.getPubKey()
pubKey, err := pkl.getPubKey()
if err != nil {
return nil, err
}
pk.CachedPubKey = pubKey
return &pk, err
pkl.CachedPubKey = pubKey
return pkl, err
}
// ValidateKey allows us to verify the sanity of a key
// after loading it from disk
func (pk PrivKeyLedgerSecp256k1) ValidateKey() error {
// PubKey returns the cached public key.
func (pkl PrivKeyLedgerSecp256k1) PubKey() tmcrypto.PubKey {
return pkl.CachedPubKey
}
// ValidateKey allows us to verify the sanity of a public key after loading it
// from disk.
func (pkl PrivKeyLedgerSecp256k1) ValidateKey() error {
// getPubKey will return an error if the ledger is not
pub, err := pk.getPubKey()
pub, err := pkl.getPubKey()
if err != nil {
return err
}
// verify this matches cached address
if !pub.Equals(pk.CachedPubKey) {
if !pub.Equals(pkl.CachedPubKey) {
return fmt.Errorf("cached key does not match retrieved key")
}
return nil
}
// AssertIsPrivKeyInner fulfils PrivKey Interface
func (pk *PrivKeyLedgerSecp256k1) AssertIsPrivKeyInner() {}
// AssertIsPrivKeyInner implements the PrivKey interface. It performs a no-op.
func (pkl *PrivKeyLedgerSecp256k1) AssertIsPrivKeyInner() {}
// Bytes fulfils PrivKey Interface - but it stores the cached pubkey so we can verify
// the same key when we reconnect to a ledger
func (pk PrivKeyLedgerSecp256k1) Bytes() []byte {
return cdc.MustMarshalBinaryBare(pk)
// Bytes implements the PrivKey interface. It stores the cached public key so
// we can verify the same key when we reconnect to a ledger.
func (pkl PrivKeyLedgerSecp256k1) Bytes() []byte {
return cdc.MustMarshalBinaryBare(pkl)
}
// Sign calls the ledger and stores the PubKey for future use
// Equals implements the PrivKey interface. It makes sure two private keys
// refer to the same public key.
func (pkl PrivKeyLedgerSecp256k1) Equals(other tmcrypto.PrivKey) bool {
if ledger, ok := other.(*PrivKeyLedgerSecp256k1); ok {
return pkl.CachedPubKey.Equals(ledger.CachedPubKey)
}
return false
}
// Sign calls the ledger and stores the PubKey for future use.
//
// Communication is checked on NewPrivKeyLedger and PrivKeyFromBytes,
// returning an error, so this should only trigger if the privkey is held
// in memory for a while before use.
func (pk PrivKeyLedgerSecp256k1) Sign(msg []byte) (tcrypto.Signature, error) {
dev, err := getLedger()
// Communication is checked on NewPrivKeyLedger and PrivKeyFromBytes, returning
// an error, so this should only trigger if the private key is held in memory
// for a while before use.
func (pkl PrivKeyLedgerSecp256k1) Sign(msg []byte) (tmcrypto.Signature, error) {
sig, err := pkl.signLedgerSecp256k1(msg)
if err != nil {
return nil, err
}
sig, err := signLedgerSecp256k1(dev, pk.Path, msg)
if err != nil {
return nil, err
}
return sig, nil
}
// PubKey returns the stored PubKey
func (pk PrivKeyLedgerSecp256k1) PubKey() tcrypto.PubKey {
return pk.CachedPubKey
return sig, nil
}
// getPubKey reads the pubkey the ledger itself
// since this involves IO, it may return an error, which is not exposed
// in the PubKey interface, so this function allows better error handling
func (pk PrivKeyLedgerSecp256k1) getPubKey() (key tcrypto.PubKey, err error) {
dev, err := getLedger()
if err != nil {
return key, fmt.Errorf("cannot connect to Ledger device - error: %v", err)
}
key, err = pubkeyLedgerSecp256k1(dev, pk.Path)
func (pkl PrivKeyLedgerSecp256k1) getPubKey() (key tmcrypto.PubKey, err error) {
key, err = pkl.pubkeyLedgerSecp256k1()
if err != nil {
return key, fmt.Errorf("please open Cosmos app on the Ledger device - error: %v", err)
}
return key, err
}
// Equals fulfils PrivKey Interface - makes sure both keys refer to the
// same
func (pk PrivKeyLedgerSecp256k1) Equals(other tcrypto.PrivKey) bool {
if ledger, ok := other.(*PrivKeyLedgerSecp256k1); ok {
return pk.CachedPubKey.Equals(ledger.CachedPubKey)
func (pkl PrivKeyLedgerSecp256k1) signLedgerSecp256k1(msg []byte) (tmcrypto.Signature, error) {
sigBytes, err := pkl.ledger.SignSECP256K1(pkl.Path, msg)
if err != nil {
return nil, err
}
return false
return tmcrypto.SignatureSecp256k1FromBytes(sigBytes), nil
}
func (pkl PrivKeyLedgerSecp256k1) pubkeyLedgerSecp256k1() (pub tmcrypto.PubKey, err error) {
key, err := pkl.ledger.GetPublicKeySECP256K1(pkl.Path)
if err != nil {
return nil, fmt.Errorf("error fetching public key: %v", err)
}
var pk tmcrypto.PubKeySecp256k1
// re-serialize in the 33-byte compressed format
cmp, err := secp256k1.ParsePubKey(key[:], secp256k1.S256())
if err != nil {
return nil, fmt.Errorf("error parsing public key: %v", err)
}
copy(pk[:], cmp.SerializeCompressed())
return pk, nil
}

View File

@ -1,25 +1,26 @@
package crypto
import (
"fmt"
"os"
"testing"
"github.com/stretchr/testify/require"
tcrypto "github.com/tendermint/tendermint/crypto"
tmcrypto "github.com/tendermint/tendermint/crypto"
)
var ledgerEnabledEnv = "TEST_WITH_LEDGER"
func TestRealLedgerSecp256k1(t *testing.T) {
if os.Getenv("WITH_LEDGER") == "" {
t.Skip("Set WITH_LEDGER to run code on real ledger")
if os.Getenv(ledgerEnabledEnv) == "" {
t.Skip(fmt.Sprintf("Set '%s' to run code on a real ledger", ledgerEnabledEnv))
}
msg := []byte("kuhehfeohg")
msg := []byte("{\"account_number\":\"3\",\"chain_id\":\"1234\",\"fee\":{\"amount\":[{\"amount\":\"150\",\"denom\":\"atom\"}],\"gas\":\"5000\"},\"memo\":\"memo\",\"msgs\":[[\"%s\"]],\"sequence\":\"6\"}")
path := DerivationPath{44, 60, 0, 0, 0}
priv, err := NewPrivKeyLedgerSecp256k1(path)
require.Nil(t, err, "%+v", err)
require.Nil(t, err, "%s", err)
pub := priv.PubKey()
sig, err := priv.Sign(msg)
require.Nil(t, err)
@ -27,24 +28,23 @@ func TestRealLedgerSecp256k1(t *testing.T) {
valid := pub.VerifyBytes(msg, sig)
require.True(t, valid)
// now, let's serialize the key and make sure it still works
bs := priv.Bytes()
priv2, err := tcrypto.PrivKeyFromBytes(bs)
// now, let's serialize the public key and make sure it still works
bs := priv.PubKey().Bytes()
pub2, err := tmcrypto.PubKeyFromBytes(bs)
require.Nil(t, err, "%+v", err)
// make sure we get the same pubkey when we load from disk
pub2 := priv2.PubKey()
require.Equal(t, pub, pub2)
// signing with the loaded key should match the original pubkey
sig, err = priv2.Sign(msg)
sig, err = priv.Sign(msg)
require.Nil(t, err)
valid = pub.VerifyBytes(msg, sig)
require.True(t, valid)
// make sure pubkeys serialize properly as well
bs = pub.Bytes()
bpub, err := tcrypto.PubKeyFromBytes(bs)
bpub, err := tmcrypto.PubKeyFromBytes(bs)
require.NoError(t, err)
require.Equal(t, pub, bpub)
}
@ -52,8 +52,8 @@ func TestRealLedgerSecp256k1(t *testing.T) {
// TestRealLedgerErrorHandling calls. These tests assume
// the ledger is not plugged in....
func TestRealLedgerErrorHandling(t *testing.T) {
if os.Getenv("WITH_LEDGER") != "" {
t.Skip("Skipping on WITH_LEDGER as it tests unplugged cases")
if os.Getenv(ledgerEnabledEnv) != "" {
t.Skip(fmt.Sprintf("Unset '%s' to run code as if without a real Ledger", ledgerEnabledEnv))
}
// first, try to generate a key, must return an error

View File

@ -30,7 +30,7 @@ func ExportCmd(ctx *Context, cdc *wire.Codec, appExporter AppExporter) *cobra.Co
return err
}
doc.AppStateJSON = appState
doc.AppState = appState
doc.Validators = validators
encoded, err := wire.MarshalJSONIndent(cdc, doc)

View File

@ -346,9 +346,9 @@ func readOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey {
// error is returned if building or writing the configuration to file fails.
func writeGenesisFile(cdc *wire.Codec, genesisFile, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error {
genDoc := tmtypes.GenesisDoc{
ChainID: chainID,
Validators: validators,
AppStateJSON: appState,
ChainID: chainID,
Validators: validators,
AppState: appState,
}
if err := genDoc.ValidateAndComplete(); err != nil {

View File

@ -77,16 +77,21 @@ func interceptLoadConfig() (conf *cfg.Config, err error) {
rootDir := tmpConf.RootDir
configFilePath := filepath.Join(rootDir, "config/config.toml")
// Intercept only if the file doesn't already exist
if _, err := os.Stat(configFilePath); os.IsNotExist(err) {
// the following parse config is needed to create directories
sdkDefaultConfig, _ := tcmd.ParseConfig()
sdkDefaultConfig.ProfListenAddress = "prof_laddr=localhost:6060"
sdkDefaultConfig.P2P.RecvRate = 5120000
sdkDefaultConfig.P2P.SendRate = 5120000
cfg.WriteConfigFile(configFilePath, sdkDefaultConfig)
conf, _ = tcmd.ParseConfig()
conf.ProfListenAddress = "localhost:6060"
conf.P2P.RecvRate = 5120000
conf.P2P.SendRate = 5120000
conf.Consensus.TimeoutCommit = 5000
cfg.WriteConfigFile(configFilePath, conf)
// Fall through, just so that its parsed into memory.
}
conf, err = tcmd.ParseConfig()
if conf == nil {
conf, err = tcmd.ParseConfig()
}
return
}

View File

@ -17,9 +17,9 @@ func TestIsPositiveCoin(t *testing.T) {
{NewCoin("a", -1), false},
}
for _, tc := range cases {
for tcIndex, tc := range cases {
res := tc.inputOne.IsPositive()
require.Equal(t, tc.expected, res)
require.Equal(t, tc.expected, res, "%s positivity is incorrect, tc #%d", tc.inputOne.String(), tcIndex)
}
}
@ -33,9 +33,9 @@ func TestIsNotNegativeCoin(t *testing.T) {
{NewCoin("a", -1), false},
}
for _, tc := range cases {
for tcIndex, tc := range cases {
res := tc.inputOne.IsNotNegative()
require.Equal(t, tc.expected, res)
require.Equal(t, tc.expected, res, "%s not-negativity is incorrect, tc #%d", tc.inputOne.String(), tcIndex)
}
}
@ -52,9 +52,9 @@ func TestSameDenomAsCoin(t *testing.T) {
{NewCoin("steak", -11), NewCoin("steak", 10), true},
}
for _, tc := range cases {
for tcIndex, tc := range cases {
res := tc.inputOne.SameDenomAs(tc.inputTwo)
require.Equal(t, tc.expected, res)
require.Equal(t, tc.expected, res, "coin denominations didn't match, tc #%d", tcIndex)
}
}
@ -70,9 +70,9 @@ func TestIsGTECoin(t *testing.T) {
{NewCoin("a", 1), NewCoin("b", 1), false},
}
for _, tc := range cases {
for tcIndex, tc := range cases {
res := tc.inputOne.IsGTE(tc.inputTwo)
require.Equal(t, tc.expected, res)
require.Equal(t, tc.expected, res, "coin GTE relation is incorrect, tc #%d", tcIndex)
}
}
@ -89,9 +89,9 @@ func TestIsEqualCoin(t *testing.T) {
{NewCoin("steak", -11), NewCoin("steak", 10), false},
}
for _, tc := range cases {
for tcIndex, tc := range cases {
res := tc.inputOne.IsEqual(tc.inputTwo)
require.Equal(t, tc.expected, res)
require.Equal(t, tc.expected, res, "coin equality relation is incorrect, tc #%d", tcIndex)
}
}
@ -106,9 +106,9 @@ func TestPlusCoin(t *testing.T) {
{NewCoin("asdf", -4), NewCoin("asdf", 5), NewCoin("asdf", 1)},
}
for _, tc := range cases {
for tcIndex, tc := range cases {
res := tc.inputOne.Plus(tc.inputTwo)
require.Equal(t, tc.expected, res)
require.Equal(t, tc.expected, res, "sum of coins is incorrect, tc #%d", tcIndex)
}
tc := struct {
@ -132,9 +132,9 @@ func TestMinusCoin(t *testing.T) {
{NewCoin("asdf", 10), NewCoin("asdf", 1), NewCoin("asdf", 9)},
}
for _, tc := range cases {
for tcIndex, tc := range cases {
res := tc.inputOne.Minus(tc.inputTwo)
require.Equal(t, tc.expected, res)
require.Equal(t, tc.expected, res, "difference of coins is incorrect, tc #%d", tcIndex)
}
tc := struct {
@ -212,10 +212,10 @@ func TestPlusCoins(t *testing.T) {
{Coins{{"A", negone}, {"B", zero}}, Coins{{"A", zero}, {"B", zero}}, Coins{{"A", negone}}},
}
for _, tc := range cases {
for tcIndex, tc := range cases {
res := tc.inputOne.Plus(tc.inputTwo)
assert.True(t, res.IsValid())
require.Equal(t, tc.expected, res)
require.Equal(t, tc.expected, res, "sum of coins is incorrect, tc #%d", tcIndex)
}
}
@ -242,12 +242,12 @@ func TestParse(t *testing.T) {
{"5foo-bar", false, nil}, // once more, only letters in coin name
}
for _, tc := range cases {
for tcIndex, tc := range cases {
res, err := ParseCoins(tc.input)
if !tc.valid {
require.NotNil(t, err, "%s: %#v", tc.input, res)
require.NotNil(t, err, "%s: %#v. tc #%d", tc.input, res, tcIndex)
} else if assert.Nil(t, err, "%s: %+v", tc.input, err) {
require.Equal(t, tc.expected, res)
require.Equal(t, tc.expected, res, "coin parsing was incorrect, tc #%d", tcIndex)
}
}
@ -296,10 +296,10 @@ func TestSortCoins(t *testing.T) {
{dup, false, false},
}
for _, tc := range cases {
require.Equal(t, tc.before, tc.coins.IsValid())
for tcIndex, tc := range cases {
require.Equal(t, tc.before, tc.coins.IsValid(), "coin validity is incorrect before sorting, tc #%d", tcIndex)
tc.coins.Sort()
require.Equal(t, tc.after, tc.coins.IsValid())
require.Equal(t, tc.after, tc.coins.IsValid(), "coin validity is incorrect after sorting, tc #%d", tcIndex)
}
}

View File

@ -234,7 +234,7 @@ func (r *Rat) UnmarshalAmino(text string) (err error) {
//___________________________________________________________________________________
// helpers
// test if two rat arrays are the equal
// test if two rat arrays are equal
func RatsEqual(r1s, r2s []Rat) bool {
if len(r1s) != len(r2s) {
return false

View File

@ -48,22 +48,22 @@ func TestNewFromDecimal(t *testing.T) {
{"0.foobar.", true, Rat{}},
}
for _, tc := range tests {
for tcIndex, tc := range tests {
res, err := NewRatFromDecimal(tc.decimalStr, 4)
if tc.expErr {
require.NotNil(t, err, tc.decimalStr)
require.NotNil(t, err, tc.decimalStr, "error expected, tc #%d", tcIndex)
} else {
require.Nil(t, err, tc.decimalStr)
require.True(t, res.Equal(tc.exp), tc.decimalStr)
require.Nil(t, err, tc.decimalStr, "unexpected error, tc #%d", tcIndex)
require.True(t, res.Equal(tc.exp), tc.decimalStr, "equality was incorrect, tc #%d", tcIndex)
}
// negative tc
res, err = NewRatFromDecimal("-"+tc.decimalStr, 4)
if tc.expErr {
require.NotNil(t, err, tc.decimalStr)
require.NotNil(t, err, tc.decimalStr, "error expected (negative case), tc #%d", tcIndex)
} else {
require.Nil(t, err, tc.decimalStr)
require.True(t, res.Equal(tc.exp.Mul(NewRat(-1))), tc.decimalStr)
require.Nil(t, err, tc.decimalStr, "unexpected error (negative case), tc #%d", tcIndex)
require.True(t, res.Equal(tc.exp.Mul(NewRat(-1))), tc.decimalStr, "equality was incorrect (negative case), tc #%d", tcIndex)
}
}
}
@ -99,10 +99,10 @@ func TestEqualities(t *testing.T) {
{NewRat(-1, 7), NewRat(-3, 7), true, false, false},
}
for _, tc := range tests {
require.Equal(t, tc.gt, tc.r1.GT(tc.r2))
require.Equal(t, tc.lt, tc.r1.LT(tc.r2))
require.Equal(t, tc.eq, tc.r1.Equal(tc.r2))
for tcIndex, tc := range tests {
require.Equal(t, tc.gt, tc.r1.GT(tc.r2), "GT result is incorrect, tc #%d", tcIndex)
require.Equal(t, tc.lt, tc.r1.LT(tc.r2), "LT result is incorrect, tc #%d", tcIndex)
require.Equal(t, tc.eq, tc.r1.Equal(tc.r2), "equality result is incorrect, tc #%d", tcIndex)
}
}
@ -135,15 +135,15 @@ func TestArithmetic(t *testing.T) {
{NewRat(100), NewRat(1, 7), NewRat(100, 7), NewRat(700), NewRat(701, 7), NewRat(699, 7)},
}
for _, tc := range tests {
require.True(t, tc.resMul.Equal(tc.r1.Mul(tc.r2)), "r1 %v, r2 %v", tc.r1.Rat, tc.r2.Rat)
require.True(t, tc.resAdd.Equal(tc.r1.Add(tc.r2)), "r1 %v, r2 %v", tc.r1.Rat, tc.r2.Rat)
require.True(t, tc.resSub.Equal(tc.r1.Sub(tc.r2)), "r1 %v, r2 %v", tc.r1.Rat, tc.r2.Rat)
for tcIndex, tc := range tests {
require.True(t, tc.resMul.Equal(tc.r1.Mul(tc.r2)), "r1 %v, r2 %v. tc #%d", tc.r1.Rat, tc.r2.Rat, tcIndex)
require.True(t, tc.resAdd.Equal(tc.r1.Add(tc.r2)), "r1 %v, r2 %v. tc #%d", tc.r1.Rat, tc.r2.Rat, tcIndex)
require.True(t, tc.resSub.Equal(tc.r1.Sub(tc.r2)), "r1 %v, r2 %v. tc #%d", tc.r1.Rat, tc.r2.Rat, tcIndex)
if tc.r2.Num().IsZero() { // panic for divide by zero
require.Panics(t, func() { tc.r1.Quo(tc.r2) })
} else {
require.True(t, tc.resDiv.Equal(tc.r1.Quo(tc.r2)), "r1 %v, r2 %v", tc.r1.Rat, tc.r2.Rat)
require.True(t, tc.resDiv.Equal(tc.r1.Quo(tc.r2)), "r1 %v, r2 %v. tc #%d", tc.r1.Rat, tc.r2.Rat, tcIndex)
}
}
}
@ -168,9 +168,9 @@ func TestEvaluate(t *testing.T) {
{NewRat(113, 12), 9},
}
for _, tc := range tests {
require.Equal(t, tc.res, tc.r1.RoundInt64(), "%v", tc.r1)
require.Equal(t, tc.res*-1, tc.r1.Mul(NewRat(-1)).RoundInt64(), "%v", tc.r1.Mul(NewRat(-1)))
for tcIndex, tc := range tests {
require.Equal(t, tc.res, tc.r1.RoundInt64(), "%v. tc #%d", tc.r1, tcIndex)
require.Equal(t, tc.res*-1, tc.r1.Mul(NewRat(-1)).RoundInt64(), "%v. tc #%d", tc.r1.Mul(NewRat(-1)), tcIndex)
}
}
@ -192,10 +192,10 @@ func TestRound(t *testing.T) {
{NewRat(1, 2), NewRat(1, 2), 1000},
}
for _, tc := range tests {
require.Equal(t, tc.res, tc.r.Round(tc.precFactor), "%v", tc.r)
for tcIndex, tc := range tests {
require.Equal(t, tc.res, tc.r.Round(tc.precFactor), "%v", tc.r, "incorrect rounding, tc #%d", tcIndex)
negR1, negRes := tc.r.Mul(NewRat(-1)), tc.res.Mul(NewRat(-1))
require.Equal(t, negRes, negR1.Round(tc.precFactor), "%v", negR1)
require.Equal(t, negRes, negR1.Round(tc.precFactor), "%v", negR1, "incorrect rounding (negative case), tc #%d", tcIndex)
}
}
@ -211,8 +211,8 @@ func TestToLeftPadded(t *testing.T) {
{NewRat(1000, 3), 8, "00000333"},
{NewRat(1000, 3), 12, "000000000333"},
}
for _, tc := range tests {
require.Equal(t, tc.res, tc.rat.ToLeftPadded(tc.digits))
for tcIndex, tc := range tests {
require.Equal(t, tc.res, tc.rat.ToLeftPadded(tc.digits), "incorrect left padding, tc #%d", tcIndex)
}
}
@ -296,11 +296,13 @@ func TestRatsEqual(t *testing.T) {
{[]Rat{NewRat(1), NewRat(0)}, []Rat{NewRat(1), NewRat(0)}, true},
{[]Rat{NewRat(1), NewRat(0)}, []Rat{NewRat(0), NewRat(1)}, false},
{[]Rat{NewRat(1), NewRat(0)}, []Rat{NewRat(1)}, false},
{[]Rat{NewRat(1), NewRat(2)}, []Rat{NewRat(2), NewRat(4)}, false},
{[]Rat{NewRat(3), NewRat(18)}, []Rat{NewRat(1), NewRat(6)}, false},
}
for _, tc := range tests {
require.Equal(t, tc.eq, RatsEqual(tc.r1s, tc.r2s))
require.Equal(t, tc.eq, RatsEqual(tc.r2s, tc.r1s))
for tcIndex, tc := range tests {
require.Equal(t, tc.eq, RatsEqual(tc.r1s, tc.r2s), "equality of rational arrays is incorrect, tc #%d", tcIndex)
require.Equal(t, tc.eq, RatsEqual(tc.r2s, tc.r1s), "equality of rational arrays is incorrect (converse), tc #%d", tcIndex)
}
}

View File

@ -29,10 +29,10 @@ func TestSortJSON(t *testing.T) {
wantErr: false},
}
for _, tc := range cases {
for tcIndex, tc := range cases {
got, err := SortJSON([]byte(tc.unsortedJSON))
if tc.wantErr != (err != nil) {
t.Fatalf("got %t, want: %t, err=%s", err != nil, tc.wantErr, err)
t.Fatalf("got %t, want: %t, tc #%d, err=%s", err != nil, tc.wantErr, tcIndex, err)
}
require.Equal(t, string(got), tc.want)
}

View File

@ -2,10 +2,10 @@
package version
const Maj = "0"
const Min = "21"
const Min = "22"
const Fix = "0"
const Version = "0.21.0"
const Version = "0.22.0"
// GitCommit set by build flags
var GitCommit = ""

View File

@ -158,7 +158,7 @@ func GetCmdVote(cdc *wire.Codec) *cobra.Command {
return err
}
fmt.Printf("Vote[Voter:%s,ProposalID:%d,Option:%s]", bechVoter, msg.ProposalID, msg.Option)
fmt.Printf("Vote[Voter:%s,ProposalID:%d,Option:%s]", bechVoter, msg.ProposalID, msg.Option.String())
// build and sign the transaction, then broadcast to Tendermint
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))

View File

@ -128,18 +128,24 @@ func (keeper Keeper) activateVotingPeriod(ctx sdk.Context, proposal Proposal) {
// =====================================================
// Procedures
var (
defaultMinDeposit int64 = 10
defaultMaxDepositPeriod int64 = 10000
defaultVotingPeriod int64 = 10000
)
// Gets procedure from store. TODO: move to global param store and allow for updating of this
func (keeper Keeper) GetDepositProcedure() DepositProcedure {
return DepositProcedure{
MinDeposit: sdk.Coins{sdk.NewCoin("steak", 10)},
MaxDepositPeriod: 200,
MinDeposit: sdk.Coins{sdk.NewCoin("steak", defaultMinDeposit)},
MaxDepositPeriod: defaultMaxDepositPeriod,
}
}
// Gets procedure from store. TODO: move to global param store and allow for updating of this
func (keeper Keeper) GetVotingProcedure() VotingProcedure {
return VotingProcedure{
VotingPeriod: 200,
VotingPeriod: defaultVotingPeriod,
}
}

View File

@ -10,6 +10,13 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// overwrite defaults for testing
func init() {
defaultMinDeposit = 10
defaultMaxDepositPeriod = 200
defaultVotingPeriod = 200
}
func TestGetSetProposal(t *testing.T) {
mapp, keeper, _, _, _, _ := getMockApp(t, 0)
mapp.BeginBlock(abci.RequestBeginBlock{})

View File

@ -60,7 +60,7 @@ type TextProposal struct {
Description string `json:"description"` // Description of the proposal
ProposalType ProposalKind `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}
Status ProposalStatus `json:"string"` // Status of the Proposal {Pending, Active, Passed, Rejected}
Status ProposalStatus `json:"proposal_status"` // Status of the Proposal {Pending, Active, Passed, Rejected}
SubmitBlock int64 `json:"submit_block"` // Height of the block where TxGovSubmitProposal was included
TotalDeposit sdk.Coins `json:"total_deposit"` // Current deposit on this proposal. Initial value is set at InitialDeposit
@ -184,7 +184,7 @@ func (pt ProposalKind) Format(s fmt.State, verb rune) {
case 's':
s.Write([]byte(fmt.Sprintf("%s", pt.String())))
default:
s.Write([]byte(fmt.Sprintf("%v", pt)))
s.Write([]byte(fmt.Sprintf("%v", byte(pt))))
}
}
@ -283,6 +283,6 @@ func (status ProposalStatus) Format(s fmt.State, verb rune) {
case 's':
s.Write([]byte(fmt.Sprintf("%s", status.String())))
default:
s.Write([]byte(fmt.Sprintf("%v", status)))
s.Write([]byte(fmt.Sprintf("%v", byte(status))))
}
}

405
x/params/keeper.go Normal file
View File

@ -0,0 +1,405 @@
package params
import (
"fmt"
"reflect"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
)
// Keeper manages global parameter store
type Keeper struct {
cdc *wire.Codec
key sdk.StoreKey
}
// NewKeeper constructs a new Keeper
func NewKeeper(cdc *wire.Codec, key sdk.StoreKey) Keeper {
return Keeper{
cdc: cdc,
key: key,
}
}
// InitKeeper constructs a new Keeper with initial parameters
func InitKeeper(ctx sdk.Context, cdc *wire.Codec, key sdk.StoreKey, params ...interface{}) Keeper {
if len(params)%2 != 0 {
panic("Odd params list length for InitKeeper")
}
k := NewKeeper(cdc, key)
for i := 0; i < len(params); i += 2 {
k.set(ctx, params[i].(string), params[i+1])
}
return k
}
// get automatically unmarshalls parameter to pointer
func (k Keeper) get(ctx sdk.Context, key string, ptr interface{}) error {
store := ctx.KVStore(k.key)
bz := store.Get([]byte(key))
return k.cdc.UnmarshalBinary(bz, ptr)
}
// getRaw returns raw byte slice
func (k Keeper) getRaw(ctx sdk.Context, key string) []byte {
store := ctx.KVStore(k.key)
return store.Get([]byte(key))
}
// set automatically marshalls and type check parameter
func (k Keeper) set(ctx sdk.Context, key string, param interface{}) error {
store := ctx.KVStore(k.key)
bz := store.Get([]byte(key))
if bz != nil {
ptrty := reflect.PtrTo(reflect.TypeOf(param))
ptr := reflect.New(ptrty).Interface()
if k.cdc.UnmarshalBinary(bz, ptr) != nil {
return fmt.Errorf("Type mismatch with stored param and provided param")
}
}
bz, err := k.cdc.MarshalBinary(param)
if err != nil {
return err
}
store.Set([]byte(key), bz)
return nil
}
// setRaw sets raw byte slice
func (k Keeper) setRaw(ctx sdk.Context, key string, param []byte) {
store := ctx.KVStore(k.key)
store.Set([]byte(key), param)
}
// Getter returns readonly struct
func (k Keeper) Getter() Getter {
return Getter{k}
}
// Setter returns read/write struct
func (k Keeper) Setter() Setter {
return Setter{Getter{k}}
}
// Getter exposes methods related with only getting params
type Getter struct {
k Keeper
}
// Get exposes get
func (k Getter) Get(ctx sdk.Context, key string, ptr interface{}) error {
return k.k.get(ctx, key, ptr)
}
// GetRaw exposes getRaw
func (k Getter) GetRaw(ctx sdk.Context, key string) []byte {
return k.k.getRaw(ctx, key)
}
// GetString is helper function for string params
func (k Getter) GetString(ctx sdk.Context, key string) (res string, err error) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
err = k.k.cdc.UnmarshalBinary(bz, &res)
return
}
// GetBool is helper function for bool params
func (k Getter) GetBool(ctx sdk.Context, key string) (res bool, err error) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
err = k.k.cdc.UnmarshalBinary(bz, &res)
return
}
// GetInt16 is helper function for int16 params
func (k Getter) GetInt16(ctx sdk.Context, key string) (res int16, err error) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
err = k.k.cdc.UnmarshalBinary(bz, &res)
return
}
// GetInt32 is helper function for int32 params
func (k Getter) GetInt32(ctx sdk.Context, key string) (res int32, err error) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
err = k.k.cdc.UnmarshalBinary(bz, &res)
return
}
// GetInt64 is helper function for int64 params
func (k Getter) GetInt64(ctx sdk.Context, key string) (res int64, err error) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
err = k.k.cdc.UnmarshalBinary(bz, &res)
return
}
// GetUint16 is helper function for uint16 params
func (k Getter) GetUint16(ctx sdk.Context, key string) (res uint16, err error) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
err = k.k.cdc.UnmarshalBinary(bz, &res)
return
}
// GetUint32 is helper function for uint32 params
func (k Getter) GetUint32(ctx sdk.Context, key string) (res uint32, err error) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
err = k.k.cdc.UnmarshalBinary(bz, &res)
return
}
// GetUint64 is helper function for uint64 params
func (k Getter) GetUint64(ctx sdk.Context, key string) (res uint64, err error) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
err = k.k.cdc.UnmarshalBinary(bz, &res)
return
}
// GetInt is helper function for sdk.Int params
func (k Getter) GetInt(ctx sdk.Context, key string) (res sdk.Int, err error) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
err = k.k.cdc.UnmarshalBinary(bz, &res)
return
}
// GetUint is helper function for sdk.Uint params
func (k Getter) GetUint(ctx sdk.Context, key string) (res sdk.Uint, err error) {
store := ctx.KVStore(k.k.key)
bz := store.Get([]byte(key))
err = k.k.cdc.UnmarshalBinary(bz, &res)
return
}
// GetRat is helper function for rat params
func (k Getter) GetRat(ctx sdk.Context, key string) (res sdk.Rat, 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
}
// GetRatWithDefault is helper function for sdk.Rat params with default value
func (k Getter) GetRatWithDefault(ctx sdk.Context, key string, def sdk.Rat) (res sdk.Rat) {
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)
}
}
// SetRat is helper function for rat params
func (k Setter) SetRat(ctx sdk.Context, key string, param sdk.Rat) {
if err := k.k.set(ctx, key, param); err != nil {
panic(err)
}
}

280
x/params/keeper_test.go Normal file
View File

@ -0,0 +1,280 @@
package params
import (
"testing"
"github.com/stretchr/testify/assert"
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/store"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
)
func defaultContext(key sdk.StoreKey) sdk.Context {
db := dbm.NewMemDB()
cms := store.NewCommitMultiStore(db)
cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db)
cms.LoadLatestVersion()
ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger())
return ctx
}
func TestKeeper(t *testing.T) {
kvs := []struct {
key string
param int64
}{
{"key1", 10},
{"key2", 55},
{"key3", 182},
{"key4", 17582},
{"key5", 2768554},
}
skey := sdk.NewKVStoreKey("test")
ctx := defaultContext(skey)
setter := NewKeeper(wire.NewCodec(), skey).Setter()
for _, kv := range kvs {
err := setter.Set(ctx, kv.key, kv.param)
assert.Nil(t, err)
}
for _, kv := range kvs {
var param int64
err := setter.Get(ctx, kv.key, &param)
assert.Nil(t, err)
assert.Equal(t, kv.param, param)
}
cdc := wire.NewCodec()
for _, kv := range kvs {
var param int64
bz := setter.GetRaw(ctx, kv.key)
err := cdc.UnmarshalBinary(bz, &param)
assert.Nil(t, err)
assert.Equal(t, kv.param, param)
}
for _, kv := range kvs {
var param bool
err := setter.Get(ctx, kv.key, &param)
assert.NotNil(t, err)
}
for _, kv := range kvs {
err := setter.Set(ctx, kv.key, true)
assert.NotNil(t, err)
}
}
func TestGetter(t *testing.T) {
key := sdk.NewKVStoreKey("test")
ctx := defaultContext(key)
keeper := NewKeeper(wire.NewCodec(), key)
g := keeper.Getter()
s := keeper.Setter()
kvs := []struct {
key string
param interface{}
}{
{"string", "test"},
{"bool", true},
{"int16", int16(1)},
{"int32", int32(1)},
{"int64", int64(1)},
{"uint16", uint16(1)},
{"uint32", uint32(1)},
{"uint64", uint64(1)},
{"int", sdk.NewInt(1)},
{"uint", sdk.NewUint(1)},
{"rat", sdk.NewRat(1)},
}
assert.NotPanics(t, func() { s.SetString(ctx, kvs[0].key, "test") })
assert.NotPanics(t, func() { s.SetBool(ctx, kvs[1].key, true) })
assert.NotPanics(t, func() { s.SetInt16(ctx, kvs[2].key, int16(1)) })
assert.NotPanics(t, func() { s.SetInt32(ctx, kvs[3].key, int32(1)) })
assert.NotPanics(t, func() { s.SetInt64(ctx, kvs[4].key, int64(1)) })
assert.NotPanics(t, func() { s.SetUint16(ctx, kvs[5].key, uint16(1)) })
assert.NotPanics(t, func() { s.SetUint32(ctx, kvs[6].key, uint32(1)) })
assert.NotPanics(t, func() { s.SetUint64(ctx, kvs[7].key, uint64(1)) })
assert.NotPanics(t, func() { s.SetInt(ctx, kvs[8].key, sdk.NewInt(1)) })
assert.NotPanics(t, func() { s.SetUint(ctx, kvs[9].key, sdk.NewUint(1)) })
assert.NotPanics(t, func() { s.SetRat(ctx, kvs[10].key, sdk.NewRat(1)) })
var res interface{}
var err error
// String
def0 := "default"
res, err = g.GetString(ctx, kvs[0].key)
assert.Nil(t, err)
assert.Equal(t, kvs[0].param, res)
_, err = g.GetString(ctx, "invalid")
assert.NotNil(t, err)
res = g.GetStringWithDefault(ctx, kvs[0].key, def0)
assert.Equal(t, kvs[0].param, res)
res = g.GetStringWithDefault(ctx, "invalid", def0)
assert.Equal(t, def0, res)
// Bool
def1 := false
res, err = g.GetBool(ctx, kvs[1].key)
assert.Nil(t, err)
assert.Equal(t, kvs[1].param, res)
_, err = g.GetBool(ctx, "invalid")
assert.NotNil(t, err)
res = g.GetBoolWithDefault(ctx, kvs[1].key, def1)
assert.Equal(t, kvs[1].param, res)
res = g.GetBoolWithDefault(ctx, "invalid", def1)
assert.Equal(t, def1, res)
// Int16
def2 := int16(0)
res, err = g.GetInt16(ctx, kvs[2].key)
assert.Nil(t, err)
assert.Equal(t, kvs[2].param, res)
_, err = g.GetInt16(ctx, "invalid")
assert.NotNil(t, err)
res = g.GetInt16WithDefault(ctx, kvs[2].key, def2)
assert.Equal(t, kvs[2].param, res)
res = g.GetInt16WithDefault(ctx, "invalid", def2)
assert.Equal(t, def2, res)
// Int32
def3 := int32(0)
res, err = g.GetInt32(ctx, kvs[3].key)
assert.Nil(t, err)
assert.Equal(t, kvs[3].param, res)
_, err = g.GetInt32(ctx, "invalid")
assert.NotNil(t, err)
res = g.GetInt32WithDefault(ctx, kvs[3].key, def3)
assert.Equal(t, kvs[3].param, res)
res = g.GetInt32WithDefault(ctx, "invalid", def3)
assert.Equal(t, def3, res)
// Int64
def4 := int64(0)
res, err = g.GetInt64(ctx, kvs[4].key)
assert.Nil(t, err)
assert.Equal(t, kvs[4].param, res)
_, err = g.GetInt64(ctx, "invalid")
assert.NotNil(t, err)
res = g.GetInt64WithDefault(ctx, kvs[4].key, def4)
assert.Equal(t, kvs[4].param, res)
res = g.GetInt64WithDefault(ctx, "invalid", def4)
assert.Equal(t, def4, res)
// Uint16
def5 := uint16(0)
res, err = g.GetUint16(ctx, kvs[5].key)
assert.Nil(t, err)
assert.Equal(t, kvs[5].param, res)
_, err = g.GetUint16(ctx, "invalid")
assert.NotNil(t, err)
res = g.GetUint16WithDefault(ctx, kvs[5].key, def5)
assert.Equal(t, kvs[5].param, res)
res = g.GetUint16WithDefault(ctx, "invalid", def5)
assert.Equal(t, def5, res)
// Uint32
def6 := uint32(0)
res, err = g.GetUint32(ctx, kvs[6].key)
assert.Nil(t, err)
assert.Equal(t, kvs[6].param, res)
_, err = g.GetUint32(ctx, "invalid")
assert.NotNil(t, err)
res = g.GetUint32WithDefault(ctx, kvs[6].key, def6)
assert.Equal(t, kvs[6].param, res)
res = g.GetUint32WithDefault(ctx, "invalid", def6)
assert.Equal(t, def6, res)
// Uint64
def7 := uint64(0)
res, err = g.GetUint64(ctx, kvs[7].key)
assert.Nil(t, err)
assert.Equal(t, kvs[7].param, res)
_, err = g.GetUint64(ctx, "invalid")
assert.NotNil(t, err)
res = g.GetUint64WithDefault(ctx, kvs[7].key, def7)
assert.Equal(t, kvs[7].param, res)
res = g.GetUint64WithDefault(ctx, "invalid", def7)
assert.Equal(t, def7, res)
// Int
def8 := sdk.NewInt(0)
res, err = g.GetInt(ctx, kvs[8].key)
assert.Nil(t, err)
assert.Equal(t, kvs[8].param, res)
_, err = g.GetInt(ctx, "invalid")
assert.NotNil(t, err)
res = g.GetIntWithDefault(ctx, kvs[8].key, def8)
assert.Equal(t, kvs[8].param, res)
res = g.GetIntWithDefault(ctx, "invalid", def8)
assert.Equal(t, def8, res)
// Uint
def9 := sdk.NewUint(0)
res, err = g.GetUint(ctx, kvs[9].key)
assert.Nil(t, err)
assert.Equal(t, kvs[9].param, res)
_, err = g.GetUint(ctx, "invalid")
assert.NotNil(t, err)
res = g.GetUintWithDefault(ctx, kvs[9].key, def9)
assert.Equal(t, kvs[9].param, res)
res = g.GetUintWithDefault(ctx, "invalid", def9)
assert.Equal(t, def9, res)
// Rat
def10 := sdk.NewRat(0)
res, err = g.GetRat(ctx, kvs[10].key)
assert.Nil(t, err)
assert.Equal(t, kvs[10].param, res)
_, err = g.GetRat(ctx, "invalid")
assert.NotNil(t, err)
res = g.GetRatWithDefault(ctx, kvs[10].key, def10)
assert.Equal(t, kvs[10].param, res)
res = g.GetRatWithDefault(ctx, "invalid", def10)
assert.Equal(t, def10, res)
}

36
x/params/msg_status.go Normal file
View File

@ -0,0 +1,36 @@
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
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) (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
}
}

View File

@ -7,6 +7,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/mock"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/cosmos/cosmos-sdk/x/stake"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
@ -26,15 +27,18 @@ func getMockApp(t *testing.T) (*mock.App, stake.Keeper, Keeper) {
RegisterWire(mapp.Cdc)
keyStake := sdk.NewKVStoreKey("stake")
keySlashing := sdk.NewKVStoreKey("slashing")
keyParams := sdk.NewKVStoreKey("params")
coinKeeper := bank.NewKeeper(mapp.AccountMapper)
paramsKeeper := params.NewKeeper(mapp.Cdc, keyParams)
stakeKeeper := stake.NewKeeper(mapp.Cdc, keyStake, coinKeeper, mapp.RegisterCodespace(stake.DefaultCodespace))
keeper := NewKeeper(mapp.Cdc, keySlashing, stakeKeeper, mapp.RegisterCodespace(DefaultCodespace))
keeper := NewKeeper(mapp.Cdc, keySlashing, stakeKeeper, paramsKeeper.Getter(), mapp.RegisterCodespace(DefaultCodespace))
mapp.Router().AddRoute("stake", stake.NewHandler(stakeKeeper))
mapp.Router().AddRoute("slashing", NewHandler(keeper))
mapp.SetEndBlocker(getEndBlocker(stakeKeeper))
mapp.SetInitChainer(getInitChainer(mapp, stakeKeeper))
require.NoError(t, mapp.CompleteSetup([]*sdk.KVStoreKey{keyStake, keySlashing}))
require.NoError(t, mapp.CompleteSetup([]*sdk.KVStoreKey{keyStake, keySlashing, keyParams}))
return mapp, stakeKeeper, keeper
}

View File

@ -11,7 +11,7 @@ import (
func TestCannotUnrevokeUnlessRevoked(t *testing.T) {
// initial setup
ctx, ck, sk, keeper := createTestInput(t)
ctx, ck, sk, _, keeper := createTestInput(t)
slh := NewHandler(keeper)
amtInt := int64(100)
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)

View File

@ -5,6 +5,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/tendermint/tendermint/crypto"
)
@ -13,17 +14,19 @@ type Keeper struct {
storeKey sdk.StoreKey
cdc *wire.Codec
validatorSet sdk.ValidatorSet
params params.Getter
// codespace
codespace sdk.CodespaceType
}
// NewKeeper creates a slashing keeper
func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, vs sdk.ValidatorSet, codespace sdk.CodespaceType) Keeper {
func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, vs sdk.ValidatorSet, params params.Getter, codespace sdk.CodespaceType) Keeper {
keeper := Keeper{
storeKey: key,
cdc: cdc,
validatorSet: vs,
params: params,
codespace: codespace,
}
return keeper
@ -37,16 +40,17 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, pubkey crypto.PubKey, infracti
address := sdk.ValAddress(pubkey.Address())
// Double sign too old
if age > MaxEvidenceAge {
logger.Info(fmt.Sprintf("Ignored double sign from %s at height %d, age of %d past max age of %d", pubkey.Address(), infractionHeight, age, MaxEvidenceAge))
maxEvidenceAge := k.MaxEvidenceAge(ctx)
if age > maxEvidenceAge {
logger.Info(fmt.Sprintf("Ignored double sign from %s at height %d, age of %d past max age of %d", pubkey.Address(), infractionHeight, age, maxEvidenceAge))
return
}
// Double sign confirmed
logger.Info(fmt.Sprintf("Confirmed double sign from %s at height %d, age of %d less than max age of %d", pubkey.Address(), infractionHeight, age, MaxEvidenceAge))
logger.Info(fmt.Sprintf("Confirmed double sign from %s at height %d, age of %d less than max age of %d", pubkey.Address(), infractionHeight, age, maxEvidenceAge))
// Slash validator
k.validatorSet.Slash(ctx, pubkey, infractionHeight, power, SlashFractionDoubleSign)
k.validatorSet.Slash(ctx, pubkey, infractionHeight, power, k.SlashFractionDoubleSign(ctx))
// Revoke validator
k.validatorSet.Revoke(ctx, pubkey)
@ -56,7 +60,7 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, pubkey crypto.PubKey, infracti
if !found {
panic(fmt.Sprintf("Expected signing info for validator %s but not found", address))
}
signInfo.JailedUntil = time + DoubleSignUnbondDuration
signInfo.JailedUntil = time + k.DoubleSignUnbondDuration(ctx)
k.setValidatorSigningInfo(ctx, address, signInfo)
}
@ -73,7 +77,7 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey,
// If this validator has never been seen before, construct a new SigningInfo with the correct start height
signInfo = NewValidatorSigningInfo(height, 0, 0, 0)
}
index := signInfo.IndexOffset % SignedBlocksWindow
index := signInfo.IndexOffset % k.SignedBlocksWindow(ctx)
signInfo.IndexOffset++
// Update signed block bit array & counter
@ -93,15 +97,15 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey,
}
if !signed {
logger.Info(fmt.Sprintf("Absent validator %s at height %d, %d signed, threshold %d", pubkey.Address(), height, signInfo.SignedBlocksCounter, MinSignedPerWindow))
logger.Info(fmt.Sprintf("Absent validator %s at height %d, %d signed, threshold %d", pubkey.Address(), height, signInfo.SignedBlocksCounter, k.MinSignedPerWindow(ctx)))
}
minHeight := signInfo.StartHeight + SignedBlocksWindow
if height > minHeight && signInfo.SignedBlocksCounter < MinSignedPerWindow {
minHeight := signInfo.StartHeight + k.SignedBlocksWindow(ctx)
if height > minHeight && signInfo.SignedBlocksCounter < k.MinSignedPerWindow(ctx) {
// Downtime confirmed, slash, revoke, and jail the validator
logger.Info(fmt.Sprintf("Validator %s past min height of %d and below signed blocks threshold of %d", pubkey.Address(), minHeight, MinSignedPerWindow))
k.validatorSet.Slash(ctx, pubkey, height, power, SlashFractionDowntime)
logger.Info(fmt.Sprintf("Validator %s past min height of %d and below signed blocks threshold of %d", pubkey.Address(), minHeight, k.MinSignedPerWindow(ctx)))
k.validatorSet.Slash(ctx, pubkey, height, power, k.SlashFractionDowntime(ctx))
k.validatorSet.Revoke(ctx, pubkey)
signInfo.JailedUntil = ctx.BlockHeader().Time + DowntimeUnbondDuration
signInfo.JailedUntil = ctx.BlockHeader().Time + k.DowntimeUnbondDuration(ctx)
}
// Set the updated signing info

View File

@ -14,10 +14,9 @@ import (
// Have to change these parameters for tests
// lest the tests take forever
func init() {
SignedBlocksWindow = 1000
MinSignedPerWindow = SignedBlocksWindow / 2
DowntimeUnbondDuration = 60 * 60
DoubleSignUnbondDuration = 60 * 60
defaultSignedBlocksWindow = 1000
defaultDowntimeUnbondDuration = 60 * 60
defaultDoubleSignUnbondDuration = 60 * 60
}
// Test that a validator is slashed correctly
@ -25,7 +24,7 @@ func init() {
func TestHandleDoubleSign(t *testing.T) {
// initial setup
ctx, ck, sk, keeper := createTestInput(t)
ctx, ck, sk, _, keeper := createTestInput(t)
amtInt := int64(100)
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt))
@ -46,7 +45,7 @@ func TestHandleDoubleSign(t *testing.T) {
sk.Unrevoke(ctx, val)
// power should be reduced
require.Equal(t, sdk.NewRatFromInt(amt).Mul(sdk.NewRat(19).Quo(sdk.NewRat(20))), sk.Validator(ctx, addr).GetPower())
ctx = ctx.WithBlockHeader(abci.Header{Time: 1 + MaxEvidenceAge})
ctx = ctx.WithBlockHeader(abci.Header{Time: 1 + keeper.MaxEvidenceAge(ctx)})
// double sign past max age
keeper.handleDoubleSign(ctx, val, 0, 0, amtInt)
@ -58,7 +57,7 @@ func TestHandleDoubleSign(t *testing.T) {
func TestHandleAbsentValidator(t *testing.T) {
// initial setup
ctx, ck, sk, keeper := createTestInput(t)
ctx, ck, sk, _, keeper := createTestInput(t)
amtInt := int64(100)
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
sh := stake.NewHandler(sk)
@ -77,24 +76,24 @@ func TestHandleAbsentValidator(t *testing.T) {
height := int64(0)
// 1000 first blocks OK
for ; height < SignedBlocksWindow; height++ {
for ; height < keeper.SignedBlocksWindow(ctx); height++ {
ctx = ctx.WithBlockHeight(height)
keeper.handleValidatorSignature(ctx, val, amtInt, true)
}
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address()))
require.True(t, found)
require.Equal(t, int64(0), info.StartHeight)
require.Equal(t, SignedBlocksWindow, info.SignedBlocksCounter)
require.Equal(t, keeper.SignedBlocksWindow(ctx), info.SignedBlocksCounter)
// 500 blocks missed
for ; height < SignedBlocksWindow+(SignedBlocksWindow-MinSignedPerWindow); height++ {
for ; height < keeper.SignedBlocksWindow(ctx)+(keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)); height++ {
ctx = ctx.WithBlockHeight(height)
keeper.handleValidatorSignature(ctx, val, amtInt, false)
}
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address()))
require.True(t, found)
require.Equal(t, int64(0), info.StartHeight)
require.Equal(t, SignedBlocksWindow-MinSignedPerWindow, info.SignedBlocksCounter)
require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx), info.SignedBlocksCounter)
// validator should be bonded still
validator, _ := sk.GetValidatorByPubKey(ctx, val)
@ -108,7 +107,7 @@ func TestHandleAbsentValidator(t *testing.T) {
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address()))
require.True(t, found)
require.Equal(t, int64(0), info.StartHeight)
require.Equal(t, SignedBlocksWindow-MinSignedPerWindow-1, info.SignedBlocksCounter)
require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)-1, info.SignedBlocksCounter)
// validator should have been revoked
validator, _ = sk.GetValidatorByPubKey(ctx, val)
@ -119,7 +118,7 @@ func TestHandleAbsentValidator(t *testing.T) {
require.False(t, got.IsOK())
// unrevocation should succeed after jail expiration
ctx = ctx.WithBlockHeader(abci.Header{Time: DowntimeUnbondDuration + 1})
ctx = ctx.WithBlockHeader(abci.Header{Time: keeper.DowntimeUnbondDuration(ctx) + 1})
got = slh(ctx, NewMsgUnrevoke(addr))
require.True(t, got.IsOK())
@ -135,7 +134,7 @@ func TestHandleAbsentValidator(t *testing.T) {
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address()))
require.True(t, found)
require.Equal(t, height, info.StartHeight)
require.Equal(t, SignedBlocksWindow-MinSignedPerWindow-1, info.SignedBlocksCounter)
require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)-1, info.SignedBlocksCounter)
// validator should not be immediately revoked again
height++
@ -145,14 +144,14 @@ func TestHandleAbsentValidator(t *testing.T) {
require.Equal(t, sdk.Bonded, validator.GetStatus())
// 500 signed blocks
nextHeight := height + MinSignedPerWindow + 1
nextHeight := height + keeper.MinSignedPerWindow(ctx) + 1
for ; height < nextHeight; height++ {
ctx = ctx.WithBlockHeight(height)
keeper.handleValidatorSignature(ctx, val, amtInt, false)
}
// validator should be revoked again after 500 unsigned blocks
nextHeight = height + MinSignedPerWindow + 1
nextHeight = height + keeper.MinSignedPerWindow(ctx) + 1
for ; height <= nextHeight; height++ {
ctx = ctx.WithBlockHeight(height)
keeper.handleValidatorSignature(ctx, val, amtInt, false)
@ -166,7 +165,7 @@ func TestHandleAbsentValidator(t *testing.T) {
// and that they are not immediately revoked
func TestHandleNewValidator(t *testing.T) {
// initial setup
ctx, ck, sk, keeper := createTestInput(t)
ctx, ck, sk, _, keeper := createTestInput(t)
addr, val, amt := addrs[0], pks[0], int64(100)
sh := stake.NewHandler(sk)
got := sh(ctx, newTestMsgCreateValidator(addr, val, sdk.NewInt(amt)))
@ -176,16 +175,16 @@ func TestHandleNewValidator(t *testing.T) {
require.Equal(t, sdk.NewRat(amt), sk.Validator(ctx, addr).GetPower())
// 1000 first blocks not a validator
ctx = ctx.WithBlockHeight(SignedBlocksWindow + 1)
ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 1)
// Now a validator, for two blocks
keeper.handleValidatorSignature(ctx, val, 100, true)
ctx = ctx.WithBlockHeight(SignedBlocksWindow + 2)
ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 2)
keeper.handleValidatorSignature(ctx, val, 100, false)
info, found := keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address()))
require.True(t, found)
require.Equal(t, int64(SignedBlocksWindow+1), info.StartHeight)
require.Equal(t, int64(keeper.SignedBlocksWindow(ctx)+1), info.StartHeight)
require.Equal(t, int64(2), info.IndexOffset)
require.Equal(t, int64(1), info.SignedBlocksCounter)
require.Equal(t, int64(0), info.JailedUntil)

View File

@ -4,39 +4,75 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// nolint
const (
MaxEvidenceAgeKey = "slashing/MaxEvidenceAge"
SignedBlocksWindowKey = "slashing/SignedBlocksWindow"
MinSignedPerWindowKey = "slashing/MinSignedPerWindow"
DoubleSignUnbondDurationKey = "slashing/DoubleSignUnbondDuration"
DowntimeUnbondDurationKey = "slashing/DowntimeUnbondDuration"
SlashFractionDoubleSignKey = "slashing/SlashFractionDoubleSign"
SlashFractionDowntimeKey = "slashing/SlashFractionDowntime"
)
// MaxEvidenceAge - Max age for evidence - 21 days (3 weeks)
// MaxEvidenceAge = 60 * 60 * 24 * 7 * 3
func (k Keeper) MaxEvidenceAge(ctx sdk.Context) int64 {
return k.params.GetInt64WithDefault(ctx, MaxEvidenceAgeKey, defaultMaxEvidenceAge)
}
// SignedBlocksWindow - sliding window for downtime slashing
func (k Keeper) SignedBlocksWindow(ctx sdk.Context) int64 {
return k.params.GetInt64WithDefault(ctx, SignedBlocksWindowKey, defaultSignedBlocksWindow)
}
// Downtime slashing thershold - default 50%
func (k Keeper) MinSignedPerWindow(ctx sdk.Context) int64 {
minSignedPerWindow := k.params.GetRatWithDefault(ctx, MinSignedPerWindowKey, defaultMinSignedPerWindow)
signedBlocksWindow := k.SignedBlocksWindow(ctx)
return sdk.NewRat(signedBlocksWindow).Mul(minSignedPerWindow).RoundInt64()
}
// Double-sign unbond duration
func (k Keeper) DoubleSignUnbondDuration(ctx sdk.Context) int64 {
return k.params.GetInt64WithDefault(ctx, DoubleSignUnbondDurationKey, defaultDoubleSignUnbondDuration)
}
// Downtime unbond duration
func (k Keeper) DowntimeUnbondDuration(ctx sdk.Context) int64 {
return k.params.GetInt64WithDefault(ctx, DowntimeUnbondDurationKey, defaultDowntimeUnbondDuration)
}
// SlashFractionDoubleSign - currently default 5%
func (k Keeper) SlashFractionDoubleSign(ctx sdk.Context) sdk.Rat {
return k.params.GetRatWithDefault(ctx, SlashFractionDoubleSignKey, defaultSlashFractionDoubleSign)
}
// SlashFractionDowntime - currently default 1%
func (k Keeper) SlashFractionDowntime(ctx sdk.Context) sdk.Rat {
return k.params.GetRatWithDefault(ctx, SlashFractionDowntimeKey, defaultSlashFractionDowntime)
}
// declared as var because of keeper_test.go
// TODO: make it const or parameter of NewKeeper
var (
// MaxEvidenceAge - Max age for evidence - 21 days (3 weeks)
// TODO Should this be a governance parameter or just modifiable with SoftwareUpgradeProposals?
// MaxEvidenceAge = 60 * 60 * 24 * 7 * 3
// defaultMaxEvidenceAge = 60 * 60 * 24 * 7 * 3
// TODO Temporarily set to 2 minutes for testnets.
MaxEvidenceAge int64 = 60 * 2
defaultMaxEvidenceAge int64 = 60 * 2
// SignedBlocksWindow - sliding window for downtime slashing
// TODO Governance parameter?
// TODO Temporarily set to 40000 blocks for testnets
SignedBlocksWindow int64 = 40000
// Downtime slashing threshold - 50%
// TODO Governance parameter?
MinSignedPerWindow = SignedBlocksWindow / 2
// Downtime unbond duration
// TODO Governance parameter?
// TODO Temporarily set to five minutes for testnets
DowntimeUnbondDuration int64 = 60 * 5
defaultDoubleSignUnbondDuration int64 = 60 * 5
// Double-sign unbond duration
// TODO Governance parameter?
// TODO Temporarily set to five minutes for testnets
DoubleSignUnbondDuration int64 = 60 * 5
)
var (
// SlashFractionDoubleSign - currently 5%
// TODO Governance parameter?
SlashFractionDoubleSign = sdk.NewRat(1).Quo(sdk.NewRat(20))
// SlashFractionDowntime - currently 1%
// TODO Governance parameter?
SlashFractionDowntime = sdk.NewRat(1).Quo(sdk.NewRat(100))
// TODO Temporarily set to 100 blocks for testnets
defaultSignedBlocksWindow int64 = 100
// TODO Temporarily set to 10 minutes for testnets
defaultDowntimeUnbondDuration int64 = 60 * 10
defaultMinSignedPerWindow sdk.Rat = sdk.NewRat(1, 2)
defaultSlashFractionDoubleSign = sdk.NewRat(1).Quo(sdk.NewRat(20))
defaultSlashFractionDowntime = sdk.NewRat(1).Quo(sdk.NewRat(100))
)

View File

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

View File

@ -17,6 +17,7 @@ import (
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/cosmos/cosmos-sdk/x/stake"
)
@ -46,21 +47,24 @@ func createTestCodec() *wire.Codec {
return cdc
}
func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, Keeper) {
func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, params.Setter, Keeper) {
keyAcc := sdk.NewKVStoreKey("acc")
keyStake := sdk.NewKVStoreKey("stake")
keySlashing := sdk.NewKVStoreKey("slashing")
keyParams := sdk.NewKVStoreKey("params")
db := dbm.NewMemDB()
ms := store.NewCommitMultiStore(db)
ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db)
ms.MountStoreWithDB(keyStake, sdk.StoreTypeIAVL, db)
ms.MountStoreWithDB(keySlashing, sdk.StoreTypeIAVL, db)
ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db)
err := ms.LoadLatestVersion()
require.Nil(t, err)
ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewTMLogger(os.Stdout))
cdc := createTestCodec()
accountMapper := auth.NewAccountMapper(cdc, keyAcc, auth.ProtoBaseAccount)
ck := bank.NewKeeper(accountMapper)
params := params.NewKeeper(cdc, keyParams)
sk := stake.NewKeeper(cdc, keyStake, ck, stake.DefaultCodespace)
genesis := stake.DefaultGenesisState()
@ -75,8 +79,8 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, Keep
})
}
require.Nil(t, err)
keeper := NewKeeper(cdc, keySlashing, sk, DefaultCodespace)
return ctx, ck, sk, keeper
keeper := NewKeeper(cdc, keySlashing, sk, params.Getter(), DefaultCodespace)
return ctx, ck, sk, params.Setter(), keeper
}
func newPubKey(pk string) (res crypto.PubKey) {

View File

@ -13,7 +13,7 @@ import (
)
func TestBeginBlocker(t *testing.T) {
ctx, ck, sk, keeper := createTestInput(t)
ctx, ck, sk, _, keeper := createTestInput(t)
addr, pk, amt := addrs[2], pks[2], sdk.NewInt(100)
// bond the validator
@ -47,7 +47,7 @@ func TestBeginBlocker(t *testing.T) {
height := int64(0)
// for 1000 blocks, mark the validator as having signed
for ; height < SignedBlocksWindow; height++ {
for ; height < keeper.SignedBlocksWindow(ctx); height++ {
ctx = ctx.WithBlockHeight(height)
req = abci.RequestBeginBlock{
Validators: []abci.SigningValidator{{
@ -59,7 +59,7 @@ func TestBeginBlocker(t *testing.T) {
}
// for 500 blocks, mark the validator as having not signed
for ; height < ((SignedBlocksWindow * 2) - MinSignedPerWindow + 1); height++ {
for ; height < ((keeper.SignedBlocksWindow(ctx) * 2) - keeper.MinSignedPerWindow(ctx) + 1); height++ {
ctx = ctx.WithBlockHeight(height)
req = abci.RequestBeginBlock{
Validators: []abci.SigningValidator{{