diff --git a/CHANGELOG.md b/CHANGELOG.md
index dabd90a514..be7f7017f8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,7 +18,7 @@ BREAKING CHANGES
* The keys sub-module is now in the SDK
* Various other fixes
* [auth] Signers of a transaction now only sign over their own account and sequence number
-* [auth] Removed MsgChangePubKey
+* [auth] Removed MsgChangePubKey
* [auth] Removed SetPubKey from account mapper
* [auth] AltBytes renamed to Memo, now a string, max 100 characters, costs a bit of gas
* [types] `GetMsg()` -> `GetMsgs()` as txs wrap many messages
@@ -104,6 +104,7 @@ IMPROVEMENTS
* [keys] improve error message when deleting non-existent key
* [gaiacli] improve error messages on `send` and `account` commands
* added contributing guidelines
+* [docs] Added commands for governance CLI on testnet README
BUG FIXES
* [x/slashing] \#1510 Unrevoked validators cannot un-revoke themselves
@@ -129,8 +130,11 @@ BUG FIXES
* \#1461 - CLI tests now no longer reset your local environment data
* \#1505 - `gaiacli stake validator` no longer panics if validator doesn't exist
* \#1565 - fix cliff validator persisting when validator set shrinks from max
+* \#1287 - prevent zero power validators at genesis
+* [x/stake] fix bug when unbonding/redelegating using `--shares-percent`
* \#1010 - two validators can't bond with the same pubkey anymore
+
## 0.19.0
*June 13, 2018*
diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go
index c8c178229b..0d9356960b 100644
--- a/baseapp/baseapp.go
+++ b/baseapp/baseapp.go
@@ -554,7 +554,6 @@ func getState(app *BaseApp, mode runTxMode) *state {
// txBytes may be nil in some cases, eg. in tests.
// Also, in the future we may support "internal" transactions.
-// nolint: gocyclo
func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk.Result) {
//NOTE: GasWanted should be returned by the AnteHandler.
// GasUsed is determined by the GasMeter.
diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go
index b355c4ed51..72defe3012 100644
--- a/cmd/gaia/app/app.go
+++ b/cmd/gaia/app/app.go
@@ -164,7 +164,11 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
}
// load the initial stake information
- stake.InitGenesis(ctx, app.stakeKeeper, genesisState.StakeData)
+ err = stake.InitGenesis(ctx, app.stakeKeeper, genesisState.StakeData)
+ if err != nil {
+ panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
+ // return sdk.ErrGenesisParse("").TraceCause(err, "")
+ }
gov.InitGenesis(ctx, app.govKeeper, gov.DefaultGenesisState())
diff --git a/cmd/gaia/cmd/gaiadebug/hack.go b/cmd/gaia/cmd/gaiadebug/hack.go
index ddc8466c76..b06328d134 100644
--- a/cmd/gaia/cmd/gaiadebug/hack.go
+++ b/cmd/gaia/cmd/gaiadebug/hack.go
@@ -228,8 +228,7 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
var genesisState gaia.GenesisState
err := app.cdc.UnmarshalJSON(stateJSON, &genesisState)
if err != nil {
- 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, "")
}
// load the accounts
@@ -239,7 +238,10 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
}
// load the initial stake information
- stake.InitGenesis(ctx, app.stakeKeeper, genesisState.StakeData)
- return abci.ResponseInitChain{}
+ err = stake.InitGenesis(ctx, app.stakeKeeper, genesisState.StakeData)
+ if err != nil {
+ panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468 // return sdk.ErrGenesisParse("").TraceCause(err, "")
+ }
+ return abci.ResponseInitChain{}
}
diff --git a/cmd/gaia/testnets/README.md b/cmd/gaia/testnets/README.md
index e8d1f83e4d..86dc62e74f 100644
--- a/cmd/gaia/testnets/README.md
+++ b/cmd/gaia/testnets/README.md
@@ -310,11 +310,11 @@ WantedBy=multi-user.target
## Delegating to a Validator
-On the upcoming mainnet, you can delegate `atom` to a validator. These [delegators](https://cosmos.network/resources/delegators) can receive part of the validator's fee revenue. Read more about the [Cosmos Token Model](https://github.com/cosmos/cosmos/raw/master/Cosmos_Token_Model.pdf).
+On the upcoming mainnet, you can delegate `Atom` to a validator. These [delegators](https://cosmos.network/resources/delegators) can receive part of the validator's fee revenue. Read more about the [Cosmos Token Model](https://github.com/cosmos/cosmos/raw/master/Cosmos_Token_Model.pdf).
### Bond Tokens
-On the testnet, we delegate `steak` instead of `atom`. Here's how you can bond tokens to a testnet validator:
+On the testnet, we delegate `steak` instead of `Atom`. Here's how you can bond tokens to a testnet validator:
```bash
gaiacli stake delegate \
@@ -353,6 +353,90 @@ gaiacli stake delegation \
--chain-id=gaia-6002
```
+## Governance
+
+Governance is the process from which users in the Cosmos Hub can come to consensus on software upgrades, parameters of the mainnet or on custom text proposals. This is done through voting on proposals, which will be submitted by `Atom` holders on the mainnet.
+
+Some considerations about the voting process:
+
+- Voting is done by bonded `Atom` holders on a 1 bonded `Atom` 1 vote basis
+- Delegators inherit the vote of their validator if they don't vote
+- **Validators MUST vote on every proposal**. If a validator does not vote on a proposal, they will be **partially slashed**
+- Votes are tallied at the end of the voting period (2 weeks on mainnet). Each address can vote multiple times to update its `Option` value (paying the transaction fee each time), only the last casted vote will count as valid
+- Voters can choose between options `Yes`, `No`, `NoWithVeto` and `Abstain`
+At the end of the voting period, a proposal is accepted if `(YesVotes/(YesVotes+NoVotes+NoWithVetoVotes))>1/2` and `(NoWithVetoVotes/(YesVotes+NoVotes+NoWithVetoVotes))<1/3`. It is rejected otherwise
+
+For more information about the governance process and how it works, please check out the Governance module [specification](https://github.com/cosmos/cosmos-sdk/tree/develop/docs/spec/governance).
+
+### Create a Governance proposal
+
+In order to create a governance proposal, you must submit an initial deposit along with the proposal details:
+
+- `title`: Title of the proposal
+- `description`: Description of the proposal
+- `type`: Type of proposal. Must be of value _Text_ (types _SoftwareUpgrade_ and _ParameterChange_ not supported yet).
+
+```bash
+gaiacli gov submit-proposal \
+ --title=
\
+ --description= \
+ --type= \
+ --proposer= \
+ --deposit=<40steak> \
+ --from= \
+ --chain-id=gaia-7000
+```
+
+
+### Increase deposit
+
+In order for a proposal to be broadcasted to the network, the amount deposited must be above a `minDeposit` value (default: `10 steak`). If the proposal you previously created didn't meet this requirement, you can still increase the total amount deposited to activate it. Once the minimum deposit is reached, the proposal enters voting period:
+
+```bash
+gaiacli gov deposit \
+ --proposalID= \
+ --depositer= \
+ --deposit=<200steak> \
+ --from= \
+ --chain-id=gaia-7000
+```
+
+> _NOTE_: Proposals that don't meet this requirement will be deleted after `MaxDepositPeriod` is reached.
+
+#### Query proposal
+
+Once created, you can now query information of the proposal:
+
+```bash
+gaiacli gov query-proposal \
+ --proposalID= \
+ --chain-id=gaia-7000
+```
+
+### Vote on a proposal
+
+After a proposal's deposit reaches the `MinDeposit` value, the voting period opens. Bonded `Atom` holders can then cast vote on it:
+
+```bash
+gaiacli gov vote \
+ --proposalID= \
+ --voter= \
+ --option= \
+ --from= \
+ --chain-id=gaia-7000
+```
+
+#### Query vote
+
+Check the vote with the option you just submitted:
+
+```bash
+gaiacli gov query-vote \
+ --proposalID= \
+ --voter= \
+ --chain-id=gaia-7000
+```
+
## Other Operations
### Send Tokens
@@ -365,7 +449,7 @@ gaiacli send \
--to=
```
-> _*Note:*_ The `--amount` flag accepts the format `--amount=`.
+> _*NOTE:*_ The `--amount` flag accepts the format `--amount=`.
Now, view the updated balances of the origin and destination accounts:
diff --git a/x/gov/test_common.go b/x/gov/test_common.go
index 7020a780bf..ecdaa34fad 100644
--- a/x/gov/test_common.go
+++ b/x/gov/test_common.go
@@ -61,7 +61,10 @@ func getInitChainer(mapp *mock.App, keeper Keeper, stakeKeeper stake.Keeper) sdk
stakeGenesis := stake.DefaultGenesisState()
stakeGenesis.Pool.LooseTokens = 100000
- stake.InitGenesis(ctx, stakeKeeper, stakeGenesis)
+ err := stake.InitGenesis(ctx, stakeKeeper, stakeGenesis)
+ if err != nil {
+ panic(err)
+ }
InitGenesis(ctx, keeper, DefaultGenesisState())
return abci.ResponseInitChain{}
}
diff --git a/x/mock/app_test.go b/x/mock/app_test.go
index 0890b53ecc..0c548280ae 100644
--- a/x/mock/app_test.go
+++ b/x/mock/app_test.go
@@ -27,7 +27,7 @@ func (tx testMsg) Type() string { return msgType }
func (tx testMsg) GetMsg() sdk.Msg { return tx }
func (tx testMsg) GetMemo() string { return "" }
func (tx testMsg) GetSignBytes() []byte { return nil }
-func (tx testMsg) GetSigners() []sdk.AccAddress { return tx.signers }
+func (tx testMsg) GetSigners() []sdk.AccAddress { return tx.signers }
func (tx testMsg) GetSignatures() []auth.StdSignature { return nil }
func (tx testMsg) ValidateBasic() sdk.Error {
if tx.positiveNum >= 0 {
diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go
index 3b88baa7fe..333b4dc836 100644
--- a/x/slashing/app_test.go
+++ b/x/slashing/app_test.go
@@ -55,7 +55,10 @@ func getInitChainer(mapp *mock.App, keeper stake.Keeper) sdk.InitChainer {
mapp.InitChainer(ctx, req)
stakeGenesis := stake.DefaultGenesisState()
stakeGenesis.Pool.LooseTokens = 100000
- stake.InitGenesis(ctx, keeper, stakeGenesis)
+ err := stake.InitGenesis(ctx, keeper, stakeGenesis)
+ if err != nil {
+ panic(err)
+ }
return abci.ResponseInitChain{}
}
}
diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go
index c5320cb24f..b9a91f4d5b 100644
--- a/x/slashing/test_common.go
+++ b/x/slashing/test_common.go
@@ -64,7 +64,9 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, Keep
sk := stake.NewKeeper(cdc, keyStake, ck, stake.DefaultCodespace)
genesis := stake.DefaultGenesisState()
genesis.Pool.LooseTokens = initCoins.MulRaw(int64(len(addrs))).Int64()
- stake.InitGenesis(ctx, sk, genesis)
+ err = stake.InitGenesis(ctx, sk, genesis)
+ require.Nil(t, err)
+
for _, addr := range addrs {
_, _, err = ck.AddCoins(ctx, addr, sdk.Coins{
{sk.GetParams(ctx).BondDenom, initCoins},
diff --git a/x/stake/app_test.go b/x/stake/app_test.go
index aa25138c95..d1224230da 100644
--- a/x/stake/app_test.go
+++ b/x/stake/app_test.go
@@ -65,7 +65,10 @@ func getInitChainer(mapp *mock.App, keeper Keeper) sdk.InitChainer {
stakeGenesis := DefaultGenesisState()
stakeGenesis.Pool.LooseTokens = 100000
- InitGenesis(ctx, keeper, stakeGenesis)
+ err := InitGenesis(ctx, keeper, stakeGenesis)
+ if err != nil {
+ panic(err)
+ }
return abci.ResponseInitChain{}
}
@@ -83,7 +86,6 @@ func checkValidator(t *testing.T, mapp *mock.App, keeper Keeper,
return validator
}
-
func checkDelegation(
t *testing.T, mapp *mock.App, keeper Keeper, delegatorAddr,
validatorAddr sdk.AccAddress, expFound bool, expShares sdk.Rat,
diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go
index fb6cf0d10b..e4c4a9dcb1 100644
--- a/x/stake/client/cli/tx.go
+++ b/x/stake/client/cli/tx.go
@@ -240,15 +240,10 @@ func getShares(storeName string, cdc *wire.Codec, sharesAmountStr, sharesPercent
key := stake.GetDelegationKey(delegatorAddr, validatorAddr)
ctx := context.NewCoreContextFromViper()
resQuery, err := ctx.QueryStore(key, storeName)
- if err != nil {
- return sharesAmount, err
- }
- var delegation stake.Delegation
- err = cdc.UnmarshalBinary(resQuery, &delegation)
if err != nil {
return sharesAmount, errors.Errorf("cannot find delegation to determine percent Error: %v", err)
}
-
+ delegation := types.MustUnmarshalDelegation(cdc, key, resQuery)
sharesAmount = sharesPercent.Mul(delegation.Shares)
}
return
diff --git a/x/stake/genesis.go b/x/stake/genesis.go
index 1116a4748d..177f89b767 100644
--- a/x/stake/genesis.go
+++ b/x/stake/genesis.go
@@ -3,6 +3,7 @@ package stake
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/stake/types"
+ "github.com/pkg/errors"
tmtypes "github.com/tendermint/tendermint/types"
)
@@ -11,7 +12,7 @@ import (
// validator in the keeper along with manually setting the indexes. In
// addition, it also sets any delegations found in data. Finally, it updates
// the bonded validators.
-func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) {
+func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) error {
keeper.SetPool(ctx, data.Pool)
keeper.SetNewParams(ctx, data.Params)
keeper.InitIntraTxCounter(ctx)
@@ -19,6 +20,13 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) {
for _, validator := range data.Validators {
keeper.SetValidator(ctx, validator)
+ if validator.PoolShares.Amount.IsZero() {
+ return errors.Errorf("genesis validator cannot have zero pool shares, validator: %v", validator)
+ }
+ if validator.DelegatorShares.IsZero() {
+ return errors.Errorf("genesis validator cannot have zero delegator shares, validator: %v", validator)
+ }
+
// Manually set indexes for the first time
keeper.SetValidatorByPubKeyIndex(ctx, validator)
keeper.SetValidatorByPowerIndex(ctx, validator, data.Pool)
@@ -33,6 +41,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) {
}
keeper.UpdateBondedValidatorsFull(ctx)
+ return nil
}
// WriteGenesis returns a GenesisState for a given context and keeper. The
diff --git a/x/stake/genesis_test.go b/x/stake/genesis_test.go
new file mode 100644
index 0000000000..4ad5b3978d
--- /dev/null
+++ b/x/stake/genesis_test.go
@@ -0,0 +1,37 @@
+package stake
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ sdk "github.com/cosmos/cosmos-sdk/types"
+ keep "github.com/cosmos/cosmos-sdk/x/stake/keeper"
+ "github.com/cosmos/cosmos-sdk/x/stake/types"
+)
+
+func TestInitGenesis(t *testing.T) {
+ ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
+
+ pool := keeper.GetPool(ctx)
+ pool.UnbondedTokens = 1
+ pool.UnbondedShares = sdk.OneRat()
+
+ params := keeper.GetParams(ctx)
+ var delegations []Delegation
+
+ validators := []Validator{
+ NewValidator(keep.Addrs[0], keep.PKs[0], Description{Moniker: "hoop"}),
+ }
+
+ genesisState := types.NewGenesisState(pool, params, validators, delegations)
+ err := InitGenesis(ctx, keeper, genesisState)
+ require.Error(t, err)
+
+ validators[0].PoolShares.Amount = sdk.OneRat()
+ validators[0].DelegatorShares = sdk.OneRat()
+
+ genesisState = types.NewGenesisState(pool, params, validators, delegations)
+ err = InitGenesis(ctx, keeper, genesisState)
+ require.NoError(t, err)
+}
diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go
index 132add34a6..ac7fe6e5f2 100644
--- a/x/stake/keeper/key.go
+++ b/x/stake/keeper/key.go
@@ -156,7 +156,7 @@ func GetUBDsByValIndexKey(validatorAddr sdk.AccAddress) []byte {
// get the key for a redelegation
// VALUE: stake/types.RedelegationKey
-func GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.AccAddress) []byte {
+func GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.AccAddress) []byte {
return append(append(
GetREDsKey(delegatorAddr.Bytes()),
validatorSrcAddr.Bytes()...),