Merge remote-tracking branch 'origin/develop' into rigel/a-validator-on-a-cliff

This commit is contained in:
rigelrozanski
2018-07-06 18:04:49 -04:00
109 changed files with 2687 additions and 1366 deletions
+58 -60
View File
@@ -5,11 +5,9 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/mock"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/stretchr/testify/assert"
"github.com/cosmos/cosmos-sdk/x/mock"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
)
@@ -22,81 +20,86 @@ var (
addr3 = crypto.GenPrivKeyEd25519().PubKey().Address()
priv4 = crypto.GenPrivKeyEd25519()
addr4 = priv4.PubKey().Address()
coins = sdk.Coins{{"foocoin", sdk.NewInt(10)}}
fee = auth.StdFee{
sdk.Coins{{"foocoin", sdk.NewInt(0)}},
100000,
}
coins = sdk.NewCoin("foocoin", 10)
fee = auth.StdFee{sdk.Coins{sdk.NewCoin("foocoin", 0)}, 100000}
)
// initialize the mock application for this module
// getMockApp returns an initialized mock application for this module.
func getMockApp(t *testing.T) (*mock.App, Keeper) {
mapp := mock.NewApp()
mApp := mock.NewApp()
RegisterWire(mApp.Cdc)
RegisterWire(mapp.Cdc)
keyStake := sdk.NewKVStoreKey("stake")
coinKeeper := bank.NewKeeper(mapp.AccountMapper)
keeper := NewKeeper(mapp.Cdc, keyStake, coinKeeper, mapp.RegisterCodespace(DefaultCodespace))
mapp.Router().AddRoute("stake", NewHandler(keeper))
coinKeeper := bank.NewKeeper(mApp.AccountMapper)
keeper := NewKeeper(mApp.Cdc, keyStake, coinKeeper, mApp.RegisterCodespace(DefaultCodespace))
mapp.SetEndBlocker(getEndBlocker(keeper))
mapp.SetInitChainer(getInitChainer(mapp, keeper))
mApp.Router().AddRoute("stake", NewHandler(keeper))
mApp.SetEndBlocker(getEndBlocker(keeper))
mApp.SetInitChainer(getInitChainer(mApp, keeper))
require.NoError(t, mapp.CompleteSetup([]*sdk.KVStoreKey{keyStake}))
return mapp, keeper
require.NoError(t, mApp.CompleteSetup([]*sdk.KVStoreKey{keyStake}))
return mApp, keeper
}
// stake endblocker
// getEndBlocker returns a stake endblocker.
func getEndBlocker(keeper Keeper) sdk.EndBlocker {
return func(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
validatorUpdates := EndBlocker(ctx, keeper)
return abci.ResponseEndBlock{
ValidatorUpdates: validatorUpdates,
}
}
}
// overwrite the mock init chainer
// getInitChainer initializes the chainer of the mock app and sets the genesis
// state. It returns an empty ResponseInitChain.
func getInitChainer(mapp *mock.App, keeper Keeper) sdk.InitChainer {
return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
mapp.InitChainer(ctx, req)
stakeGenesis := DefaultGenesisState()
stakeGenesis.Pool.LooseTokens = 100000
InitGenesis(ctx, keeper, stakeGenesis)
return abci.ResponseInitChain{}
}
}
//__________________________________________________________________________________________
func checkValidator(t *testing.T, mapp *mock.App, keeper Keeper,
addr sdk.Address, expFound bool) Validator {
func checkValidator(
t *testing.T, mapp *mock.App, keeper Keeper,
addr sdk.Address, expFound bool,
) Validator {
ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{})
validator, found := keeper.GetValidator(ctxCheck, addr1)
require.Equal(t, expFound, found)
return validator
}
func checkDelegation(t *testing.T, mapp *mock.App, keeper Keeper, delegatorAddr,
validatorAddr sdk.Address, expFound bool, expShares sdk.Rat) {
func checkDelegation(
t *testing.T, mapp *mock.App, keeper Keeper, delegatorAddr,
validatorAddr sdk.Address, expFound bool, expShares sdk.Rat,
) {
ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{})
delegation, found := keeper.GetDelegation(ctxCheck, delegatorAddr, validatorAddr)
if expFound {
require.True(t, found)
assert.True(sdk.RatEq(t, expShares, delegation.Shares))
require.True(sdk.RatEq(t, expShares, delegation.Shares))
return
}
require.False(t, found)
}
func TestStakeMsgs(t *testing.T) {
mapp, keeper := getMockApp(t)
mApp, keeper := getMockApp(t)
genCoin := sdk.Coin{"steak", sdk.NewInt(42)}
bondCoin := sdk.Coin{"steak", sdk.NewInt(10)}
genCoin := sdk.NewCoin("steak", 42)
bondCoin := sdk.NewCoin("steak", 10)
acc1 := &auth.BaseAccount{
Address: addr1,
@@ -108,56 +111,51 @@ func TestStakeMsgs(t *testing.T) {
}
accs := []auth.Account{acc1, acc2}
mock.SetGenesis(mapp, accs)
mock.CheckBalance(t, mapp, addr1, sdk.Coins{genCoin})
mock.CheckBalance(t, mapp, addr2, sdk.Coins{genCoin})
////////////////////
// Create Validator
mock.SetGenesis(mApp, accs)
mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin})
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin})
// create validator
description := NewDescription("foo_moniker", "", "", "")
createValidatorMsg := NewMsgCreateValidator(
addr1, priv1.PubKey(), bondCoin, description,
)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{createValidatorMsg}, []int64{0}, []int64{0}, true, priv1)
mock.CheckBalance(t, mapp, addr1, sdk.Coins{genCoin.Minus(bondCoin)})
mapp.BeginBlock(abci.RequestBeginBlock{})
validator := checkValidator(t, mapp, keeper, addr1, true)
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsg}, []int64{0}, []int64{0}, true, priv1)
mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin.Minus(bondCoin)})
mApp.BeginBlock(abci.RequestBeginBlock{})
validator := checkValidator(t, mApp, keeper, addr1, true)
require.Equal(t, addr1, validator.Owner)
require.Equal(t, sdk.Bonded, validator.Status())
require.True(sdk.RatEq(t, sdk.NewRat(10), validator.PoolShares.Bonded()))
// check the bond that should have been created as well
checkDelegation(t, mapp, keeper, addr1, addr1, true, sdk.NewRat(10))
////////////////////
// Edit Validator
checkDelegation(t, mApp, keeper, addr1, addr1, true, sdk.NewRat(10))
// edit the validator
description = NewDescription("bar_moniker", "", "", "")
editValidatorMsg := NewMsgEditValidator(addr1, description)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{editValidatorMsg}, []int64{0}, []int64{1}, true, priv1)
validator = checkValidator(t, mapp, keeper, addr1, true)
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{editValidatorMsg}, []int64{0}, []int64{1}, true, priv1)
validator = checkValidator(t, mApp, keeper, addr1, true)
require.Equal(t, description, validator.Description)
////////////////////
// Delegate
mock.CheckBalance(t, mapp, addr2, sdk.Coins{genCoin})
// delegate
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin})
delegateMsg := NewMsgDelegate(addr2, addr1, bondCoin)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{0}, true, priv2)
mock.CheckBalance(t, mapp, addr2, sdk.Coins{genCoin.Minus(bondCoin)})
checkDelegation(t, mapp, keeper, addr2, addr1, true, sdk.NewRat(10))
////////////////////
// Begin Unbonding
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{0}, true, priv2)
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)})
checkDelegation(t, mApp, keeper, addr2, addr1, true, sdk.NewRat(10))
// begin unbonding
beginUnbondingMsg := NewMsgBeginUnbonding(addr2, addr1, sdk.NewRat(10))
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{1}, true, priv2)
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{1}, true, priv2)
// delegation should exist anymore
checkDelegation(t, mapp, keeper, addr2, addr1, false, sdk.Rat{})
checkDelegation(t, mApp, keeper, addr2, addr1, false, sdk.Rat{})
// balance should be the same because bonding not yet complete
mock.CheckBalance(t, mapp, addr2, sdk.Coins{genCoin.Minus(bondCoin)})
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)})
}
+23 -27
View File
@@ -11,6 +11,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/stake"
"github.com/cosmos/cosmos-sdk/x/stake/types"
)
// get the command to query a validator
@@ -30,9 +31,10 @@ func GetCmdQueryValidator(storeName string, cdc *wire.Codec) *cobra.Command {
res, err := ctx.QueryStore(key, storeName)
if err != nil {
return err
} else if len(res) == 0 {
return fmt.Errorf("No validator found with address %s", args[0])
}
validator := new(stake.Validator)
cdc.MustUnmarshalBinary(res, validator)
validator := types.MustUnmarshalValidator(cdc, addr, res)
switch viper.Get(cli.OutputFlag) {
case "text":
@@ -74,9 +76,9 @@ func GetCmdQueryValidators(storeName string, cdc *wire.Codec) *cobra.Command {
// parse out the validators
var validators []stake.Validator
for _, KV := range resKVs {
var validator stake.Validator
cdc.MustUnmarshalBinary(KV.Value, &validator)
for _, kv := range resKVs {
addr := kv.Key[1:]
validator := types.MustUnmarshalValidator(cdc, addr, kv.Value)
validators = append(validators, validator)
}
@@ -117,12 +119,12 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command {
return err
}
delAddr, err := sdk.GetValAddressHex(viper.GetString(FlagAddressDelegator))
delAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressDelegator))
if err != nil {
return err
}
key := stake.GetDelegationKey(delAddr, valAddr, cdc)
key := stake.GetDelegationKey(delAddr, valAddr)
ctx := context.NewCoreContextFromViper()
res, err := ctx.QueryStore(key, storeName)
if err != nil {
@@ -130,7 +132,7 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command {
}
// parse out the delegation
delegation := new(stake.Delegation)
delegation := types.MustUnmarshalDelegation(cdc, key, res)
switch viper.Get(cli.OutputFlag) {
case "text":
@@ -140,7 +142,6 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command {
}
fmt.Println(resp)
case "json":
cdc.MustUnmarshalBinary(res, delegation)
output, err := wire.MarshalJSONIndent(cdc, delegation)
if err != nil {
return err
@@ -169,7 +170,7 @@ func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command {
if err != nil {
return err
}
key := stake.GetDelegationsKey(delegatorAddr, cdc)
key := stake.GetDelegationsKey(delegatorAddr)
ctx := context.NewCoreContextFromViper()
resKVs, err := ctx.QuerySubspace(cdc, key, storeName)
if err != nil {
@@ -178,9 +179,8 @@ func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command {
// parse out the validators
var delegations []stake.Delegation
for _, KV := range resKVs {
var delegation stake.Delegation
cdc.MustUnmarshalBinary(KV.Value, &delegation)
for _, kv := range resKVs {
delegation := types.MustUnmarshalDelegation(cdc, kv.Key, kv.Value)
delegations = append(delegations, delegation)
}
@@ -214,7 +214,7 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co
return err
}
key := stake.GetUBDKey(delAddr, valAddr, cdc)
key := stake.GetUBDKey(delAddr, valAddr)
ctx := context.NewCoreContextFromViper()
res, err := ctx.QueryStore(key, storeName)
if err != nil {
@@ -222,7 +222,7 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co
}
// parse out the unbonding delegation
ubd := new(stake.UnbondingDelegation)
ubd := types.MustUnmarshalUBD(cdc, key, res)
switch viper.Get(cli.OutputFlag) {
case "text":
@@ -232,7 +232,6 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co
}
fmt.Println(resp)
case "json":
cdc.MustUnmarshalBinary(res, ubd)
output, err := wire.MarshalJSONIndent(cdc, ubd)
if err != nil {
return err
@@ -261,7 +260,7 @@ func GetCmdQueryUnbondingDelegations(storeName string, cdc *wire.Codec) *cobra.C
if err != nil {
return err
}
key := stake.GetUBDsKey(delegatorAddr, cdc)
key := stake.GetUBDsKey(delegatorAddr)
ctx := context.NewCoreContextFromViper()
resKVs, err := ctx.QuerySubspace(cdc, key, storeName)
if err != nil {
@@ -270,9 +269,8 @@ func GetCmdQueryUnbondingDelegations(storeName string, cdc *wire.Codec) *cobra.C
// parse out the validators
var ubds []stake.UnbondingDelegation
for _, KV := range resKVs {
var ubd stake.UnbondingDelegation
cdc.MustUnmarshalBinary(KV.Value, &ubd)
for _, kv := range resKVs {
ubd := types.MustUnmarshalUBD(cdc, kv.Key, kv.Value)
ubds = append(ubds, ubd)
}
@@ -309,7 +307,7 @@ func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command {
return err
}
key := stake.GetREDKey(delAddr, valSrcAddr, valDstAddr, cdc)
key := stake.GetREDKey(delAddr, valSrcAddr, valDstAddr)
ctx := context.NewCoreContextFromViper()
res, err := ctx.QueryStore(key, storeName)
if err != nil {
@@ -317,7 +315,7 @@ func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command {
}
// parse out the unbonding delegation
red := new(stake.Redelegation)
red := types.MustUnmarshalRED(cdc, key, res)
switch viper.Get(cli.OutputFlag) {
case "text":
@@ -327,7 +325,6 @@ func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command {
}
fmt.Println(resp)
case "json":
cdc.MustUnmarshalBinary(res, red)
output, err := wire.MarshalJSONIndent(cdc, red)
if err != nil {
return err
@@ -356,7 +353,7 @@ func GetCmdQueryRedelegations(storeName string, cdc *wire.Codec) *cobra.Command
if err != nil {
return err
}
key := stake.GetREDsKey(delegatorAddr, cdc)
key := stake.GetREDsKey(delegatorAddr)
ctx := context.NewCoreContextFromViper()
resKVs, err := ctx.QuerySubspace(cdc, key, storeName)
if err != nil {
@@ -365,9 +362,8 @@ func GetCmdQueryRedelegations(storeName string, cdc *wire.Codec) *cobra.Command
// parse out the validators
var reds []stake.Redelegation
for _, KV := range resKVs {
var red stake.Redelegation
cdc.MustUnmarshalBinary(KV.Value, &red)
for _, kv := range resKVs {
red := types.MustUnmarshalRED(cdc, kv.Key, kv.Value)
reds = append(reds, red)
}
+8 -16
View File
@@ -53,12 +53,10 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command {
msg := stake.NewMsgCreateValidator(validatorAddr, pk, amount, description)
// build and sign the transaction, then broadcast to Tendermint
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil
},
}
@@ -92,12 +90,11 @@ func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command {
// build and sign the transaction, then broadcast to Tendermint
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil
},
}
@@ -132,12 +129,11 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command {
// build and sign the transaction, then broadcast to Tendermint
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil
},
}
@@ -197,12 +193,11 @@ func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command {
// build and sign the transaction, then broadcast to Tendermint
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil
},
}
@@ -240,7 +235,7 @@ func getShares(storeName string, cdc *wire.Codec, sharesAmountStr, sharesPercent
}
// make a query to get the existing delegation shares
key := stake.GetDelegationKey(delegatorAddr, validatorAddr, cdc)
key := stake.GetDelegationKey(delegatorAddr, validatorAddr)
ctx := context.NewCoreContextFromViper()
resQuery, err := ctx.QueryStore(key, storeName)
if err != nil {
@@ -282,12 +277,11 @@ func GetCmdCompleteRedelegate(cdc *wire.Codec) *cobra.Command {
// build and sign the transaction, then broadcast to Tendermint
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil
},
}
@@ -340,12 +334,11 @@ func GetCmdBeginUnbonding(storeName string, cdc *wire.Codec) *cobra.Command {
// build and sign the transaction, then broadcast to Tendermint
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil
},
}
@@ -377,12 +370,11 @@ func GetCmdCompleteUnbonding(cdc *wire.Codec) *cobra.Command {
// build and sign the transaction, then broadcast to Tendermint
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil
},
}
+23 -20
View File
@@ -9,7 +9,9 @@ import (
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/stake"
"github.com/cosmos/cosmos-sdk/x/stake/types"
)
const storeName = "stake"
@@ -60,7 +62,7 @@ func delegationHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF
return
}
key := stake.GetDelegationKey(delegatorAddr, validatorAddr, cdc)
key := stake.GetDelegationKey(delegatorAddr, validatorAddr)
res, err := ctx.QueryStore(key, storeName)
if err != nil {
@@ -75,11 +77,10 @@ func delegationHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF
return
}
var delegation stake.Delegation
err = cdc.UnmarshalBinary(res, &delegation)
delegation, err := types.UnmarshalDelegation(cdc, key, res)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("couldn't decode delegation. Error: %s", err.Error())))
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
@@ -117,7 +118,7 @@ func ubdHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc {
return
}
key := stake.GetUBDKey(delegatorAddr, validatorAddr, cdc)
key := stake.GetUBDKey(delegatorAddr, validatorAddr)
res, err := ctx.QueryStore(key, storeName)
if err != nil {
@@ -132,11 +133,10 @@ func ubdHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc {
return
}
var ubd stake.UnbondingDelegation
err = cdc.UnmarshalBinary(res, &ubd)
ubd, err := types.UnmarshalUBD(cdc, key, res)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("couldn't decode unbonding-delegation. Error: %s", err.Error())))
w.Write([]byte(fmt.Sprintf("couldn't query unbonding-delegation. Error: %s", err.Error())))
return
}
@@ -182,7 +182,7 @@ func redHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc {
return
}
key := stake.GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr, cdc)
key := stake.GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr)
res, err := ctx.QueryStore(key, storeName)
if err != nil {
@@ -197,11 +197,10 @@ func redHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc {
return
}
var red stake.Redelegation
err = cdc.UnmarshalBinary(res, &red)
red, err := types.UnmarshalRED(cdc, key, res)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("couldn't decode redelegation. Error: %s", err.Error())))
w.Write([]byte(fmt.Sprintf("couldn't query unbonding-delegation. Error: %s", err.Error())))
return
}
@@ -291,15 +290,19 @@ func validatorsHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF
// parse out the validators
validators := make([]StakeValidatorOutput, len(kvs))
for i, kv := range kvs {
var validator stake.Validator
var bech32Validator StakeValidatorOutput
err = cdc.UnmarshalBinary(kv.Value, &validator)
if err == nil {
bech32Validator, err = bech32StakeValidatorOutput(validator)
}
addr := kv.Key[1:]
validator, err := types.UnmarshalValidator(cdc, addr, kv.Value)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("couldn't decode validator. Error: %s", err.Error())))
w.Write([]byte(fmt.Sprintf("couldn't query unbonding-delegation. Error: %s", err.Error())))
return
}
bech32Validator, err := bech32StakeValidatorOutput(validator)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
validators[i] = bech32Validator
+22 -12
View File
@@ -1,50 +1,58 @@
package stake
import (
tmtypes "github.com/tendermint/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/stake/types"
tmtypes "github.com/tendermint/tendermint/types"
)
// InitGenesis - store genesis parameters
// InitGenesis sets the pool and parameters for the provided keeper and
// initializes the IntraTxCounter. For each validator in data, it sets that
// 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) {
keeper.SetPool(ctx, data.Pool)
keeper.SetNewParams(ctx, data.Params)
keeper.InitIntraTxCounter(ctx)
for _, validator := range data.Validators {
// set validator
for _, validator := range data.Validators {
keeper.SetValidator(ctx, validator)
// manually set indexes for the first time
// Manually set indexes for the first time
keeper.SetValidatorByPubKeyIndex(ctx, validator)
keeper.SetValidatorByPowerIndex(ctx, validator, data.Pool)
if validator.Status() == sdk.Bonded {
keeper.SetValidatorBondedIndex(ctx, validator)
}
}
for _, bond := range data.Bonds {
keeper.SetDelegation(ctx, bond)
}
keeper.UpdateBondedValidatorsFull(ctx)
}
// WriteGenesis - output genesis parameters
// WriteGenesis returns a GenesisState for a given context and keeper. The
// GenesisState will contain the pool, params, validators, and bonds found in
// the keeper.
func WriteGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
pool := keeper.GetPool(ctx)
params := keeper.GetParams(ctx)
validators := keeper.GetAllValidators(ctx)
bonds := keeper.GetAllDelegations(ctx)
return types.GenesisState{
pool,
params,
validators,
bonds,
Pool: pool,
Params: params,
Validators: validators,
Bonds: bonds,
}
}
// WriteValidators - output current validator set
// WriteValidators returns a slice of bonded genesis validators.
func WriteValidators(ctx sdk.Context, keeper Keeper) (vals []tmtypes.GenesisValidator) {
keeper.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) (stop bool) {
vals = append(vals, tmtypes.GenesisValidator{
@@ -52,7 +60,9 @@ func WriteValidators(ctx sdk.Context, keeper Keeper) (vals []tmtypes.GenesisVali
Power: validator.GetPower().RoundInt64(),
Name: validator.GetMoniker(),
})
return false
})
return
}
+50 -57
View File
@@ -12,12 +12,13 @@ func (k Keeper) GetDelegation(ctx sdk.Context,
delegatorAddr, validatorAddr sdk.Address) (delegation types.Delegation, found bool) {
store := ctx.KVStore(k.storeKey)
delegatorBytes := store.Get(GetDelegationKey(delegatorAddr, validatorAddr, k.cdc))
if delegatorBytes == nil {
key := GetDelegationKey(delegatorAddr, validatorAddr)
value := store.Get(key)
if value == nil {
return delegation, false
}
k.cdc.MustUnmarshalBinary(delegatorBytes, &delegation)
delegation = types.MustUnmarshalDelegation(k.cdc, key, value)
return delegation, true
}
@@ -31,9 +32,7 @@ func (k Keeper) GetAllDelegations(ctx sdk.Context) (delegations []types.Delegati
if !iterator.Valid() {
break
}
bondBytes := iterator.Value()
var delegation types.Delegation
k.cdc.MustUnmarshalBinary(bondBytes, &delegation)
delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value())
delegations = append(delegations, delegation)
iterator.Next()
}
@@ -46,7 +45,7 @@ func (k Keeper) GetDelegations(ctx sdk.Context, delegator sdk.Address,
maxRetrieve int16) (delegations []types.Delegation) {
store := ctx.KVStore(k.storeKey)
delegatorPrefixKey := GetDelegationsKey(delegator, k.cdc)
delegatorPrefixKey := GetDelegationsKey(delegator)
iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) //smallest to largest
delegations = make([]types.Delegation, maxRetrieve)
@@ -55,9 +54,7 @@ func (k Keeper) GetDelegations(ctx sdk.Context, delegator sdk.Address,
if !iterator.Valid() || i > int(maxRetrieve-1) {
break
}
bondBytes := iterator.Value()
var delegation types.Delegation
k.cdc.MustUnmarshalBinary(bondBytes, &delegation)
delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value())
delegations[i] = delegation
iterator.Next()
}
@@ -68,14 +65,14 @@ func (k Keeper) GetDelegations(ctx sdk.Context, delegator sdk.Address,
// set the delegation
func (k Keeper) SetDelegation(ctx sdk.Context, delegation types.Delegation) {
store := ctx.KVStore(k.storeKey)
b := k.cdc.MustMarshalBinary(delegation)
store.Set(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr, k.cdc), b)
b := types.MustMarshalDelegation(k.cdc, delegation)
store.Set(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr), b)
}
// remove the delegation
func (k Keeper) RemoveDelegation(ctx sdk.Context, delegation types.Delegation) {
store := ctx.KVStore(k.storeKey)
store.Delete(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr, k.cdc))
store.Delete(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr))
}
//_____________________________________________________________________________________
@@ -85,51 +82,49 @@ func (k Keeper) GetUnbondingDelegation(ctx sdk.Context,
DelegatorAddr, ValidatorAddr sdk.Address) (ubd types.UnbondingDelegation, found bool) {
store := ctx.KVStore(k.storeKey)
ubdKey := GetUBDKey(DelegatorAddr, ValidatorAddr, k.cdc)
bz := store.Get(ubdKey)
if bz == nil {
key := GetUBDKey(DelegatorAddr, ValidatorAddr)
value := store.Get(key)
if value == nil {
return ubd, false
}
k.cdc.MustUnmarshalBinary(bz, &ubd)
ubd = types.MustUnmarshalUBD(k.cdc, key, value)
return ubd, true
}
// load all unbonding delegations from a particular validator
func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (unbondingDelegations []types.UnbondingDelegation) {
func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (ubds []types.UnbondingDelegation) {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, GetUBDsByValIndexKey(valAddr, k.cdc))
i := 0
for ; ; i++ {
iterator := sdk.KVStorePrefixIterator(store, GetUBDsByValIndexKey(valAddr))
for {
if !iterator.Valid() {
break
}
unbondingKey := iterator.Value()
unbondingBytes := store.Get(unbondingKey)
var unbondingDelegation types.UnbondingDelegation
k.cdc.MustUnmarshalBinary(unbondingBytes, &unbondingDelegation)
unbondingDelegations = append(unbondingDelegations, unbondingDelegation)
key := GetUBDKeyFromValIndexKey(iterator.Key())
value := store.Get(key)
ubd := types.MustUnmarshalUBD(k.cdc, key, value)
ubds = append(ubds, ubd)
iterator.Next()
}
iterator.Close()
return unbondingDelegations
return ubds
}
// set the unbonding delegation and associated index
func (k Keeper) SetUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDelegation) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshalBinary(ubd)
ubdKey := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr, k.cdc)
store.Set(ubdKey, bz)
store.Set(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr, k.cdc), ubdKey)
bz := types.MustMarshalUBD(k.cdc, ubd)
key := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr)
store.Set(key, bz)
store.Set(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr), []byte{}) // index, store empty bytes
}
// remove the unbonding delegation object and associated index
func (k Keeper) RemoveUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDelegation) {
store := ctx.KVStore(k.storeKey)
ubdKey := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr, k.cdc)
store.Delete(ubdKey)
store.Delete(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr, k.cdc))
key := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr)
store.Delete(key)
store.Delete(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr))
}
//_____________________________________________________________________________________
@@ -139,34 +134,32 @@ func (k Keeper) GetRedelegation(ctx sdk.Context,
DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr sdk.Address) (red types.Redelegation, found bool) {
store := ctx.KVStore(k.storeKey)
redKey := GetREDKey(DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr, k.cdc)
bz := store.Get(redKey)
if bz == nil {
key := GetREDKey(DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr)
value := store.Get(key)
if value == nil {
return red, false
}
k.cdc.MustUnmarshalBinary(bz, &red)
red = types.MustUnmarshalRED(k.cdc, key, value)
return red, true
}
// load all redelegations from a particular validator
func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (redelegations []types.Redelegation) {
func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (reds []types.Redelegation) {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, GetREDsFromValSrcIndexKey(valAddr, k.cdc))
i := 0
for ; ; i++ {
iterator := sdk.KVStorePrefixIterator(store, GetREDsFromValSrcIndexKey(valAddr))
for {
if !iterator.Valid() {
break
}
redelegationKey := iterator.Value()
redelegationBytes := store.Get(redelegationKey)
var redelegation types.Redelegation
k.cdc.MustUnmarshalBinary(redelegationBytes, &redelegation)
redelegations = append(redelegations, redelegation)
key := GetREDKeyFromValSrcIndexKey(iterator.Key())
value := store.Get(key)
red := types.MustUnmarshalRED(k.cdc, key, value)
reds = append(reds, red)
iterator.Next()
}
iterator.Close()
return redelegations
return reds
}
// has a redelegation
@@ -174,7 +167,7 @@ func (k Keeper) HasReceivingRedelegation(ctx sdk.Context,
DelegatorAddr, ValidatorDstAddr sdk.Address) bool {
store := ctx.KVStore(k.storeKey)
prefix := GetREDsByDelToValDstIndexKey(DelegatorAddr, ValidatorDstAddr, k.cdc)
prefix := GetREDsByDelToValDstIndexKey(DelegatorAddr, ValidatorDstAddr)
iterator := sdk.KVStorePrefixIterator(store, prefix) //smallest to largest
found := false
@@ -189,20 +182,20 @@ func (k Keeper) HasReceivingRedelegation(ctx sdk.Context,
// set a redelegation and associated index
func (k Keeper) SetRedelegation(ctx sdk.Context, red types.Redelegation) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshalBinary(red)
redKey := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc)
store.Set(redKey, bz)
store.Set(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc), redKey)
store.Set(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc), redKey)
bz := types.MustMarshalRED(k.cdc, red)
key := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr)
store.Set(key, bz)
store.Set(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), []byte{})
store.Set(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), []byte{})
}
// remove a redelegation object and associated index
func (k Keeper) RemoveRedelegation(ctx sdk.Context, red types.Redelegation) {
store := ctx.KVStore(k.storeKey)
redKey := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc)
redKey := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr)
store.Delete(redKey)
store.Delete(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc))
store.Delete(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc))
store.Delete(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr))
store.Delete(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr))
}
//_____________________________________________________________________________________
+39 -1
View File
@@ -179,6 +179,36 @@ func TestUnbondDelegation(t *testing.T) {
require.Equal(t, int64(4), pool.BondedTokens)
}
// Make sure that that the retrieving the delegations doesn't affect the state
func TestGetRedelegationsFromValidator(t *testing.T) {
ctx, _, keeper := CreateTestInput(t, false, 0)
rd := types.Redelegation{
DelegatorAddr: addrDels[0],
ValidatorSrcAddr: addrVals[0],
ValidatorDstAddr: addrVals[1],
CreationHeight: 0,
MinTime: 0,
SharesSrc: sdk.NewRat(5),
SharesDst: sdk.NewRat(5),
}
// set and retrieve a record
keeper.SetRedelegation(ctx, rd)
resBond, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
require.True(t, found)
// get the redelegations one time
redelegations := keeper.GetRedelegationsFromValidator(ctx, addrVals[0])
require.Equal(t, 1, len(redelegations))
require.True(t, redelegations[0].Equal(resBond))
// get the redelegations a second time, should be exactly the same
redelegations = keeper.GetRedelegationsFromValidator(ctx, addrVals[0])
require.Equal(t, 1, len(redelegations))
require.True(t, redelegations[0].Equal(resBond))
}
// tests Get/Set/Remove/Has UnbondingDelegation
func TestRedelegation(t *testing.T) {
ctx, _, keeper := CreateTestInput(t, false, 0)
@@ -201,7 +231,10 @@ func TestRedelegation(t *testing.T) {
keeper.SetRedelegation(ctx, rd)
resBond, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
require.True(t, found)
require.True(t, rd.Equal(resBond))
redelegations := keeper.GetRedelegationsFromValidator(ctx, addrVals[0])
require.Equal(t, 1, len(redelegations))
require.True(t, redelegations[0].Equal(resBond))
// check if has the redelegation
has = keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1])
@@ -211,10 +244,15 @@ func TestRedelegation(t *testing.T) {
rd.SharesSrc = sdk.NewRat(21)
rd.SharesDst = sdk.NewRat(21)
keeper.SetRedelegation(ctx, rd)
resBond, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
require.True(t, found)
require.True(t, rd.Equal(resBond))
redelegations = keeper.GetRedelegationsFromValidator(ctx, addrVals[0])
require.Equal(t, 1, len(redelegations))
require.True(t, redelegations[0].Equal(resBond))
// delete a record
keeper.RemoveRedelegation(ctx, rd)
_, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
+112 -70
View File
@@ -6,7 +6,6 @@ import (
"github.com/tendermint/tendermint/crypto"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/stake/types"
)
@@ -29,41 +28,49 @@ var (
UnbondingDelegationKey = []byte{0x0B} // key for an unbonding-delegation
UnbondingDelegationByValIndexKey = []byte{0x0C} // prefix for each key for an unbonding-delegation, by validator owner
RedelegationKey = []byte{0x0D} // key for a redelegation
RedelegationByValSrcIndexKey = []byte{0x0E} // prefix for each key for an redelegation, by validator owner
RedelegationByValDstIndexKey = []byte{0x0F} // prefix for each key for an redelegation, by validator owner
RedelegationByValSrcIndexKey = []byte{0x0E} // prefix for each key for an redelegation, by source validator owner
RedelegationByValDstIndexKey = []byte{0x0F} // prefix for each key for an redelegation, by destination validator owner
)
const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch
// get the key for the validator with address
// get the key for the validator with address.
// VALUE: stake/types.Validator
func GetValidatorKey(ownerAddr sdk.Address) []byte {
return append(ValidatorsKey, ownerAddr.Bytes()...)
}
// get the key for the validator with pubkey
// get the key for the validator with pubkey.
// VALUE: validator owner address ([]byte)
func GetValidatorByPubKeyIndexKey(pubkey crypto.PubKey) []byte {
return append(ValidatorsByPubKeyIndexKey, pubkey.Bytes()...)
}
// get the key for the current validator group, ordered like tendermint
// get the key for the current validator group
// VALUE: none (key rearrangement with GetValKeyFromValBondedIndexKey)
func GetValidatorsBondedIndexKey(ownerAddr sdk.Address) []byte {
return append(ValidatorsBondedIndexKey, ownerAddr.Bytes()...)
}
// get the power which is the key for the validator used in the power-store
func GetValidatorsByPowerIndexKey(validator types.Validator, pool types.Pool) []byte {
// NOTE the address doesn't need to be stored because counter bytes must always be different
return GetValidatorPowerRank(validator, pool)
// Get the validator owner address from ValBondedIndexKey
func GetAddressFromValBondedIndexKey(IndexKey []byte) []byte {
return IndexKey[1:] // remove prefix bytes
}
// get the power of a validator
func GetValidatorPowerRank(validator types.Validator, pool types.Pool) []byte {
// get the validator by power index. power index is the key used in the power-store,
// and represents the relative power ranking of the validator.
// VALUE: validator owner address ([]byte)
func GetValidatorsByPowerIndexKey(validator types.Validator, pool types.Pool) []byte {
// NOTE the address doesn't need to be stored because counter bytes must always be different
return getValidatorPowerRank(validator, pool)
}
// get the power ranking of a validator
func getValidatorPowerRank(validator types.Validator, pool types.Pool) []byte {
power := validator.EquivalentBondedShares(pool)
powerBytes := []byte(power.ToLeftPadded(maxDigitsForAccount)) // power big-endian (more powerful validators first)
// TODO ensure that the key will be a readable string.. probably should add seperators and have
revokedBytes := make([]byte, 1)
if validator.Revoked {
revokedBytes[0] = byte(0x01)
@@ -71,127 +78,162 @@ func GetValidatorPowerRank(validator types.Validator, pool types.Pool) []byte {
revokedBytes[0] = byte(0x00)
}
// TODO ensure that the key will be a readable string.. probably should add seperators and have
// heightBytes and counterBytes represent strings like powerBytes does
heightBytes := make([]byte, binary.MaxVarintLen64)
binary.BigEndian.PutUint64(heightBytes, ^uint64(validator.BondHeight)) // invert height (older validators first)
counterBytes := make([]byte, 2)
binary.BigEndian.PutUint16(counterBytes, ^uint16(validator.BondIntraTxCounter)) // invert counter (first txns have priority)
return append(ValidatorsByPowerIndexKey,
append(revokedBytes,
append(powerBytes,
append(heightBytes, counterBytes...)...)...)...)
return append(append(append(append(
ValidatorsByPowerIndexKey,
revokedBytes...),
powerBytes...),
heightBytes...),
counterBytes...)
}
// get the key for the accumulated update validators
// get the key for the accumulated update validators.
// VALUE: abci.Validator
// note records using these keys should never persist between blocks
func GetTendermintUpdatesKey(ownerAddr sdk.Address) []byte {
return append(TendermintUpdatesKey, ownerAddr.Bytes()...)
}
//________________________________________________________________________________
// get the key for delegator bond with validator
func GetDelegationKey(delegatorAddr, validatorAddr sdk.Address, cdc *wire.Codec) []byte {
return append(GetDelegationsKey(delegatorAddr, cdc), validatorAddr.Bytes()...)
// get the key for delegator bond with validator.
// VALUE: stake/types.Delegation
func GetDelegationKey(delegatorAddr, validatorAddr sdk.Address) []byte {
return append(GetDelegationsKey(delegatorAddr), validatorAddr.Bytes()...)
}
// get the prefix for a delegator for all validators
func GetDelegationsKey(delegatorAddr sdk.Address, cdc *wire.Codec) []byte {
res := cdc.MustMarshalBinary(&delegatorAddr)
return append(DelegationKey, res...)
func GetDelegationsKey(delegatorAddr sdk.Address) []byte {
return append(DelegationKey, delegatorAddr.Bytes()...)
}
//________________________________________________________________________________
// get the key for an unbonding delegation
func GetUBDKey(delegatorAddr, validatorAddr sdk.Address, cdc *wire.Codec) []byte {
return append(GetUBDsKey(delegatorAddr, cdc), validatorAddr.Bytes()...)
// get the key for an unbonding delegation by delegator and validator addr.
// VALUE: stake/types.UnbondingDelegation
func GetUBDKey(delegatorAddr, validatorAddr sdk.Address) []byte {
return append(
GetUBDsKey(delegatorAddr.Bytes()),
validatorAddr.Bytes()...)
}
// get the index-key for an unbonding delegation, stored by validator-index
func GetUBDByValIndexKey(delegatorAddr, validatorAddr sdk.Address, cdc *wire.Codec) []byte {
return append(GetUBDsByValIndexKey(validatorAddr, cdc), delegatorAddr.Bytes()...)
// VALUE: none (key rearrangement used)
func GetUBDByValIndexKey(delegatorAddr, validatorAddr sdk.Address) []byte {
return append(GetUBDsByValIndexKey(validatorAddr), delegatorAddr.Bytes()...)
}
// rearrange the ValIndexKey to get the UBDKey
func GetUBDKeyFromValIndexKey(IndexKey []byte) []byte {
addrs := IndexKey[1:] // remove prefix bytes
if len(addrs) != 2*sdk.AddrLen {
panic("unexpected key length")
}
valAddr := addrs[:sdk.AddrLen]
delAddr := addrs[sdk.AddrLen:]
return GetUBDKey(delAddr, valAddr)
}
//______________
// get the prefix for all unbonding delegations from a delegator
func GetUBDsKey(delegatorAddr sdk.Address, cdc *wire.Codec) []byte {
res := cdc.MustMarshalBinary(&delegatorAddr)
return append(UnbondingDelegationKey, res...)
func GetUBDsKey(delegatorAddr sdk.Address) []byte {
return append(UnbondingDelegationKey, delegatorAddr.Bytes()...)
}
// get the prefix keyspace for the indexs of unbonding delegations for a validator
func GetUBDsByValIndexKey(validatorAddr sdk.Address, cdc *wire.Codec) []byte {
res := cdc.MustMarshalBinary(&validatorAddr)
return append(UnbondingDelegationByValIndexKey, res...)
// get the prefix keyspace for the indexes of unbonding delegations for a validator
func GetUBDsByValIndexKey(validatorAddr sdk.Address) []byte {
return append(UnbondingDelegationByValIndexKey, validatorAddr.Bytes()...)
}
//________________________________________________________________________________
// get the key for a redelegation
// VALUE: stake/types.RedelegationKey
func GetREDKey(delegatorAddr, validatorSrcAddr,
validatorDstAddr sdk.Address, cdc *wire.Codec) []byte {
validatorDstAddr sdk.Address) []byte {
return append(
GetREDsKey(delegatorAddr, cdc),
append(
validatorSrcAddr.Bytes(),
validatorDstAddr.Bytes()...)...,
)
return append(append(
GetREDsKey(delegatorAddr.Bytes()),
validatorSrcAddr.Bytes()...),
validatorDstAddr.Bytes()...)
}
// get the index-key for a redelegation, stored by source-validator-index
// VALUE: none (key rearrangement used)
func GetREDByValSrcIndexKey(delegatorAddr, validatorSrcAddr,
validatorDstAddr sdk.Address, cdc *wire.Codec) []byte {
validatorDstAddr sdk.Address) []byte {
return append(
GetREDsFromValSrcIndexKey(validatorSrcAddr, cdc),
append(
delegatorAddr.Bytes(),
validatorDstAddr.Bytes()...)...,
)
return append(append(
GetREDsFromValSrcIndexKey(validatorSrcAddr),
delegatorAddr.Bytes()...),
validatorDstAddr.Bytes()...)
}
// get the index-key for a redelegation, stored by destination-validator-index
// VALUE: none (key rearrangement used)
func GetREDByValDstIndexKey(delegatorAddr, validatorSrcAddr,
validatorDstAddr sdk.Address, cdc *wire.Codec) []byte {
validatorDstAddr sdk.Address) []byte {
return append(
GetREDsToValDstIndexKey(validatorDstAddr, cdc),
append(
delegatorAddr.Bytes(),
validatorSrcAddr.Bytes()...)...,
)
return append(append(
GetREDsToValDstIndexKey(validatorDstAddr),
delegatorAddr.Bytes()...),
validatorSrcAddr.Bytes()...)
}
// rearrange the ValSrcIndexKey to get the REDKey
func GetREDKeyFromValSrcIndexKey(IndexKey []byte) []byte {
addrs := IndexKey[1:] // remove prefix bytes
if len(addrs) != 3*sdk.AddrLen {
panic("unexpected key length")
}
valSrcAddr := addrs[:sdk.AddrLen]
delAddr := addrs[sdk.AddrLen : 2*sdk.AddrLen]
valDstAddr := addrs[2*sdk.AddrLen:]
return GetREDKey(delAddr, valSrcAddr, valDstAddr)
}
// rearrange the ValDstIndexKey to get the REDKey
func GetREDKeyFromValDstIndexKey(IndexKey []byte) []byte {
addrs := IndexKey[1:] // remove prefix bytes
if len(addrs) != 3*sdk.AddrLen {
panic("unexpected key length")
}
valDstAddr := addrs[:sdk.AddrLen]
delAddr := addrs[sdk.AddrLen : 2*sdk.AddrLen]
valSrcAddr := addrs[2*sdk.AddrLen:]
return GetREDKey(delAddr, valSrcAddr, valDstAddr)
}
//______________
// get the prefix keyspace for redelegations from a delegator
func GetREDsKey(delegatorAddr sdk.Address, cdc *wire.Codec) []byte {
res := cdc.MustMarshalBinary(&delegatorAddr)
return append(RedelegationKey, res...)
func GetREDsKey(delegatorAddr sdk.Address) []byte {
return append(RedelegationKey, delegatorAddr.Bytes()...)
}
// get the prefix keyspace for all redelegations redelegating away from a source validator
func GetREDsFromValSrcIndexKey(validatorSrcAddr sdk.Address, cdc *wire.Codec) []byte {
res := cdc.MustMarshalBinary(&validatorSrcAddr)
return append(RedelegationByValSrcIndexKey, res...)
func GetREDsFromValSrcIndexKey(validatorSrcAddr sdk.Address) []byte {
return append(RedelegationByValSrcIndexKey, validatorSrcAddr.Bytes()...)
}
// get the prefix keyspace for all redelegations redelegating towards a destination validator
func GetREDsToValDstIndexKey(validatorDstAddr sdk.Address, cdc *wire.Codec) []byte {
res := cdc.MustMarshalBinary(&validatorDstAddr)
return append(RedelegationByValDstIndexKey, res...)
func GetREDsToValDstIndexKey(validatorDstAddr sdk.Address) []byte {
return append(RedelegationByValDstIndexKey, validatorDstAddr.Bytes()...)
}
// get the prefix keyspace for all redelegations redelegating towards a destination validator
// from a particular delegator
func GetREDsByDelToValDstIndexKey(delegatorAddr sdk.Address,
validatorDstAddr sdk.Address, cdc *wire.Codec) []byte {
validatorDstAddr sdk.Address) []byte {
return append(
GetREDsToValDstIndexKey(validatorDstAddr, cdc),
GetREDsToValDstIndexKey(validatorDstAddr),
delegatorAddr.Bytes()...)
}
+5 -8
View File
@@ -16,9 +16,8 @@ func (k Keeper) IterateValidators(ctx sdk.Context, fn func(index int64, validato
iterator := sdk.KVStorePrefixIterator(store, ValidatorsKey)
i := int64(0)
for ; iterator.Valid(); iterator.Next() {
bz := iterator.Value()
var validator types.Validator
k.cdc.MustUnmarshalBinary(bz, &validator)
addr := iterator.Key()[1:]
validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value())
stop := fn(i, validator) // XXX is this safe will the validator unexposed fields be able to get written to?
if stop {
break
@@ -34,7 +33,7 @@ func (k Keeper) IterateValidatorsBonded(ctx sdk.Context, fn func(index int64, va
iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey)
i := int64(0)
for ; iterator.Valid(); iterator.Next() {
address := iterator.Value()
address := GetAddressFromValBondedIndexKey(iterator.Key())
validator, found := k.GetValidator(ctx, address)
if !found {
panic(fmt.Sprintf("validator record not found for address: %v\n", address))
@@ -87,13 +86,11 @@ func (k Keeper) Delegation(ctx sdk.Context, addrDel sdk.Address, addrVal sdk.Add
// iterate through the active validator set and perform the provided function
func (k Keeper) IterateDelegations(ctx sdk.Context, delAddr sdk.Address, fn func(index int64, delegation sdk.Delegation) (stop bool)) {
store := ctx.KVStore(k.storeKey)
key := GetDelegationsKey(delAddr, k.cdc)
key := GetDelegationsKey(delAddr)
iterator := sdk.KVStorePrefixIterator(store, key)
i := int64(0)
for ; iterator.Valid(); iterator.Next() {
bz := iterator.Value()
var delegation types.Delegation
k.cdc.MustUnmarshalBinary(bz, &delegation)
delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value())
stop := fn(i, delegation) // XXX is this safe will the fields be able to get written to?
if stop {
break
+22 -22
View File
@@ -14,11 +14,11 @@ import (
// get a single validator
func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.Address) (validator types.Validator, found bool) {
store := ctx.KVStore(k.storeKey)
b := store.Get(GetValidatorKey(addr))
if b == nil {
value := store.Get(GetValidatorKey(addr))
if value == nil {
return validator, false
}
k.cdc.MustUnmarshalBinary(b, &validator)
validator = types.MustUnmarshalValidator(k.cdc, addr, value)
return validator, true
}
@@ -35,15 +35,13 @@ func (k Keeper) GetValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) (val
// set the main record holding validator details
func (k Keeper) SetValidator(ctx sdk.Context, validator types.Validator) {
store := ctx.KVStore(k.storeKey)
// set main store
bz := k.cdc.MustMarshalBinary(validator)
bz := types.MustMarshalValidator(k.cdc, validator)
store.Set(GetValidatorKey(validator.Owner), bz)
}
// validator index
func (k Keeper) SetValidatorByPubKeyIndex(ctx sdk.Context, validator types.Validator) {
store := ctx.KVStore(k.storeKey)
// set pointer by pubkey
store.Set(GetValidatorByPubKeyIndexKey(validator.PubKey), validator.Owner)
}
@@ -56,7 +54,7 @@ func (k Keeper) SetValidatorByPowerIndex(ctx sdk.Context, validator types.Valida
// validator index
func (k Keeper) SetValidatorBondedIndex(ctx sdk.Context, validator types.Validator) {
store := ctx.KVStore(k.storeKey)
store.Set(GetValidatorsBondedIndexKey(validator.Owner), validator.Owner)
store.Set(GetValidatorsBondedIndexKey(validator.Owner), []byte{})
}
// used in testing
@@ -75,9 +73,8 @@ func (k Keeper) GetAllValidators(ctx sdk.Context) (validators []types.Validator)
if !iterator.Valid() {
break
}
bz := iterator.Value()
var validator types.Validator
k.cdc.MustUnmarshalBinary(bz, &validator)
addr := iterator.Key()[1:]
validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value())
validators = append(validators, validator)
iterator.Next()
}
@@ -96,9 +93,8 @@ func (k Keeper) GetValidators(ctx sdk.Context, maxRetrieve int16) (validators []
if !iterator.Valid() || i > int(maxRetrieve-1) {
break
}
bz := iterator.Value()
var validator types.Validator
k.cdc.MustUnmarshalBinary(bz, &validator)
addr := iterator.Key()[1:]
validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value())
validators[i] = validator
iterator.Next()
}
@@ -124,7 +120,7 @@ func (k Keeper) GetValidatorsBonded(ctx sdk.Context) (validators []types.Validat
if i > int(maxValidators-1) {
panic("maxValidators is less than the number of records in ValidatorsBonded Store, store should have been updated")
}
address := iterator.Value()
address := GetAddressFromValBondedIndexKey(iterator.Key())
validator, found := k.GetValidator(ctx, address)
if !found {
panic(fmt.Sprintf("validator record not found for address: %v\n", address))
@@ -205,8 +201,7 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type
// always update the main list ordered by owner address before exiting
defer func() {
bz := k.cdc.MustMarshalBinary(validator)
store.Set(GetValidatorKey(ownerAddr), bz)
k.SetValidator(ctx, validator)
}()
// retrieve the old validator record
@@ -266,6 +261,13 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type
if updatedVal.Owner != nil { // updates to validator occurred to be updated
validator = updatedVal
}
// if decreased in power but still bonded, update Tendermint validator
// (if updatedVal is set, the validator has changed bonding status)
stillBonded := oldFound && oldValidator.Status() == sdk.Bonded && updatedVal.Owner == nil
if stillBonded && oldValidator.PoolShares.Bonded().GT(validator.PoolShares.Bonded()) {
bz := k.cdc.MustMarshalBinary(validator.ABCIValidator())
store.Set(GetTendermintUpdatesKey(ownerAddr), bz)
}
return validator
}
@@ -388,7 +390,7 @@ func (k Keeper) UpdateBondedValidatorsFull(ctx sdk.Context) {
toKickOut := make(map[string]byte)
iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey)
for ; iterator.Valid(); iterator.Next() {
ownerAddr := iterator.Value()
ownerAddr := GetAddressFromValBondedIndexKey(iterator.Key())
toKickOut[string(ownerAddr)] = 0 // set anything
}
iterator.Close()
@@ -465,8 +467,7 @@ func (k Keeper) unbondValidator(ctx sdk.Context, validator types.Validator) type
k.SetPool(ctx, pool)
// save the now unbonded validator record
bzVal := k.cdc.MustMarshalBinary(validator)
store.Set(GetValidatorKey(validator.Owner), bzVal)
k.SetValidator(ctx, validator)
// add to accumulated changes for tendermint
bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidatorZero())
@@ -493,9 +494,8 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types.
k.SetPool(ctx, pool)
// save the now bonded validator record to the three referenced stores
bzVal := k.cdc.MustMarshalBinary(validator)
store.Set(GetValidatorKey(validator.Owner), bzVal)
store.Set(GetValidatorsBondedIndexKey(validator.Owner), validator.Owner)
k.SetValidator(ctx, validator)
store.Set(GetValidatorsBondedIndexKey(validator.Owner), []byte{})
// add to accumulated changes for tendermint
bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidator())
+40
View File
@@ -675,3 +675,43 @@ func TestGetTendermintUpdatesNotValidatorCliff(t *testing.T) {
require.Equal(t, validators[0].ABCIValidatorZero(), updates[0])
require.Equal(t, validators[2].ABCIValidator(), updates[1])
}
func TestGetTendermintUpdatesPowerDecrease(t *testing.T) {
ctx, _, keeper := CreateTestInput(t, false, 1000)
amts := []int64{100, 100}
var validators [2]types.Validator
for i, amt := range amts {
pool := keeper.GetPool(ctx)
validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{})
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, amt)
keeper.SetPool(ctx, pool)
}
validators[0] = keeper.UpdateValidator(ctx, validators[0])
validators[1] = keeper.UpdateValidator(ctx, validators[1])
keeper.ClearTendermintUpdates(ctx)
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
// check initial power
require.Equal(t, sdk.NewRat(100).RoundInt64(), validators[0].GetPower().RoundInt64())
require.Equal(t, sdk.NewRat(100).RoundInt64(), validators[1].GetPower().RoundInt64())
// test multiple value change
// tendermintUpdate set: {c1, c3} -> {c1', c3'}
pool := keeper.GetPool(ctx)
validators[0], pool, _ = validators[0].RemoveDelShares(pool, sdk.NewRat(20))
validators[1], pool, _ = validators[1].RemoveDelShares(pool, sdk.NewRat(30))
keeper.SetPool(ctx, pool)
validators[0] = keeper.UpdateValidator(ctx, validators[0])
validators[1] = keeper.UpdateValidator(ctx, validators[1])
// power has changed
require.Equal(t, sdk.NewRat(80).RoundInt64(), validators[0].GetPower().RoundInt64())
require.Equal(t, sdk.NewRat(70).RoundInt64(), validators[1].GetPower().RoundInt64())
// Tendermint updates should reflect power change
updates := keeper.GetTendermintUpdates(ctx)
require.Equal(t, 2, len(updates))
require.Equal(t, validators[0].ABCIValidator(), updates[0])
require.Equal(t, validators[1].ABCIValidator(), updates[1])
}
+21 -25
View File
@@ -7,30 +7,29 @@ import (
"github.com/cosmos/cosmos-sdk/x/stake/types"
)
// keeper
type Keeper = keeper.Keeper
var NewKeeper = keeper.NewKeeper
// types
type Validator = types.Validator
type Description = types.Description
type Delegation = types.Delegation
type UnbondingDelegation = types.UnbondingDelegation
type Redelegation = types.Redelegation
type Params = types.Params
type Pool = types.Pool
type PoolShares = types.PoolShares
type MsgCreateValidator = types.MsgCreateValidator
type MsgEditValidator = types.MsgEditValidator
type MsgDelegate = types.MsgDelegate
type MsgBeginUnbonding = types.MsgBeginUnbonding
type MsgCompleteUnbonding = types.MsgCompleteUnbonding
type MsgBeginRedelegate = types.MsgBeginRedelegate
type MsgCompleteRedelegate = types.MsgCompleteRedelegate
type GenesisState = types.GenesisState
type (
Keeper = keeper.Keeper
Validator = types.Validator
Description = types.Description
Delegation = types.Delegation
UnbondingDelegation = types.UnbondingDelegation
Redelegation = types.Redelegation
Params = types.Params
Pool = types.Pool
PoolShares = types.PoolShares
MsgCreateValidator = types.MsgCreateValidator
MsgEditValidator = types.MsgEditValidator
MsgDelegate = types.MsgDelegate
MsgBeginUnbonding = types.MsgBeginUnbonding
MsgCompleteUnbonding = types.MsgCompleteUnbonding
MsgBeginRedelegate = types.MsgBeginRedelegate
MsgCompleteRedelegate = types.MsgCompleteRedelegate
GenesisState = types.GenesisState
)
var (
NewKeeper = keeper.NewKeeper
GetValidatorKey = keeper.GetValidatorKey
GetValidatorByPubKeyIndexKey = keeper.GetValidatorByPubKeyIndexKey
GetValidatorsBondedIndexKey = keeper.GetValidatorsBondedIndexKey
@@ -72,7 +71,6 @@ var (
DefaultGenesisState = types.DefaultGenesisState
RegisterWire = types.RegisterWire
// messages
NewMsgCreateValidator = types.NewMsgCreateValidator
NewMsgEditValidator = types.NewMsgEditValidator
NewMsgDelegate = types.NewMsgDelegate
@@ -82,7 +80,6 @@ var (
NewMsgCompleteRedelegate = types.NewMsgCompleteRedelegate
)
// errors
const (
DefaultCodespace = types.DefaultCodespace
CodeInvalidValidator = types.CodeInvalidValidator
@@ -126,7 +123,6 @@ var (
ErrMissingSignature = types.ErrMissingSignature
)
// tags
var (
ActionCreateValidator = tags.ActionCreateValidator
ActionEditValidator = tags.ActionEditValidator
+182 -11
View File
@@ -2,9 +2,11 @@ package types
import (
"bytes"
"errors"
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
)
// Delegation represents the bond with tokens held by an account. It is
@@ -17,7 +19,54 @@ type Delegation struct {
Height int64 `json:"height"` // Last height bond updated
}
// two are equal
type delegationValue struct {
Shares sdk.Rat
Height int64
}
// return the delegation without fields contained within the key for the store
func MustMarshalDelegation(cdc *wire.Codec, delegation Delegation) []byte {
val := delegationValue{
delegation.Shares,
delegation.Height,
}
return cdc.MustMarshalBinary(val)
}
// return the delegation without fields contained within the key for the store
func MustUnmarshalDelegation(cdc *wire.Codec, key, value []byte) Delegation {
delegation, err := UnmarshalDelegation(cdc, key, value)
if err != nil {
panic(err)
}
return delegation
}
// return the delegation without fields contained within the key for the store
func UnmarshalDelegation(cdc *wire.Codec, key, value []byte) (delegation Delegation, err error) {
var storeValue delegationValue
err = cdc.UnmarshalBinary(value, &storeValue)
if err != nil {
return
}
addrs := key[1:] // remove prefix bytes
if len(addrs) != 2*sdk.AddrLen {
err = errors.New("unexpected key length")
return
}
delAddr := sdk.Address(addrs[:sdk.AddrLen])
valAddr := sdk.Address(addrs[sdk.AddrLen:])
return Delegation{
DelegatorAddr: delAddr,
ValidatorAddr: valAddr,
Shares: storeValue.Shares,
Height: storeValue.Height,
}, nil
}
// nolint
func (d Delegation) Equal(d2 Delegation) bool {
return bytes.Equal(d.DelegatorAddr, d2.DelegatorAddr) &&
bytes.Equal(d.ValidatorAddr, d2.ValidatorAddr) &&
@@ -33,16 +82,20 @@ func (d Delegation) GetDelegator() sdk.Address { return d.DelegatorAddr }
func (d Delegation) GetValidator() sdk.Address { return d.ValidatorAddr }
func (d Delegation) GetBondShares() sdk.Rat { return d.Shares }
//Human Friendly pretty printer
// HumanReadableString returns a human readable string representation of a
// Delegation. An error is returned if the Delegation's delegator or validator
// addresses cannot be Bech32 encoded.
func (d Delegation) HumanReadableString() (string, error) {
bechAcc, err := sdk.Bech32ifyAcc(d.DelegatorAddr)
if err != nil {
return "", err
}
bechVal, err := sdk.Bech32ifyAcc(d.ValidatorAddr)
if err != nil {
return "", err
}
resp := "Delegation \n"
resp += fmt.Sprintf("Delegator: %s\n", bechAcc)
resp += fmt.Sprintf("Validator: %s\n", bechVal)
@@ -50,12 +103,9 @@ func (d Delegation) HumanReadableString() (string, error) {
resp += fmt.Sprintf("Height: %d", d.Height)
return resp, nil
}
//__________________________________________________________________
// element stored to represent the passive unbonding queue
// UnbondingDelegation reflects a delegation's passive unbonding queue.
type UnbondingDelegation struct {
DelegatorAddr sdk.Address `json:"delegator_addr"` // delegator
ValidatorAddr sdk.Address `json:"validator_addr"` // validator unbonding from owner addr
@@ -65,6 +115,59 @@ type UnbondingDelegation struct {
Balance sdk.Coin `json:"balance"` // atoms to receive at completion
}
type ubdValue struct {
CreationHeight int64
MinTime int64
InitialBalance sdk.Coin
Balance sdk.Coin
}
// return the unbonding delegation without fields contained within the key for the store
func MustMarshalUBD(cdc *wire.Codec, ubd UnbondingDelegation) []byte {
val := ubdValue{
ubd.CreationHeight,
ubd.MinTime,
ubd.InitialBalance,
ubd.Balance,
}
return cdc.MustMarshalBinary(val)
}
// unmarshal a unbonding delegation from a store key and value
func MustUnmarshalUBD(cdc *wire.Codec, key, value []byte) UnbondingDelegation {
ubd, err := UnmarshalUBD(cdc, key, value)
if err != nil {
panic(err)
}
return ubd
}
// unmarshal a unbonding delegation from a store key and value
func UnmarshalUBD(cdc *wire.Codec, key, value []byte) (ubd UnbondingDelegation, err error) {
var storeValue ubdValue
err = cdc.UnmarshalBinary(value, &storeValue)
if err != nil {
return
}
addrs := key[1:] // remove prefix bytes
if len(addrs) != 2*sdk.AddrLen {
err = errors.New("unexpected key length")
return
}
delAddr := sdk.Address(addrs[:sdk.AddrLen])
valAddr := sdk.Address(addrs[sdk.AddrLen:])
return UnbondingDelegation{
DelegatorAddr: delAddr,
ValidatorAddr: valAddr,
CreationHeight: storeValue.CreationHeight,
MinTime: storeValue.MinTime,
InitialBalance: storeValue.InitialBalance,
Balance: storeValue.Balance,
}, nil
}
// nolint
func (d UnbondingDelegation) Equal(d2 UnbondingDelegation) bool {
bz1 := MsgCdc.MustMarshalBinary(&d)
@@ -72,16 +175,20 @@ func (d UnbondingDelegation) Equal(d2 UnbondingDelegation) bool {
return bytes.Equal(bz1, bz2)
}
//Human Friendly pretty printer
// HumanReadableString returns a human readable string representation of an
// UnbondingDelegation. An error is returned if the UnbondingDelegation's
// delegator or validator addresses cannot be Bech32 encoded.
func (d UnbondingDelegation) HumanReadableString() (string, error) {
bechAcc, err := sdk.Bech32ifyAcc(d.DelegatorAddr)
if err != nil {
return "", err
}
bechVal, err := sdk.Bech32ifyAcc(d.ValidatorAddr)
if err != nil {
return "", err
}
resp := "Unbonding Delegation \n"
resp += fmt.Sprintf("Delegator: %s\n", bechAcc)
resp += fmt.Sprintf("Validator: %s\n", bechVal)
@@ -93,9 +200,7 @@ func (d UnbondingDelegation) HumanReadableString() (string, error) {
}
//__________________________________________________________________
// element stored to represent the passive redelegation queue
// Redelegation reflects a delegation's passive re-delegation queue.
type Redelegation struct {
DelegatorAddr sdk.Address `json:"delegator_addr"` // delegator
ValidatorSrcAddr sdk.Address `json:"validator_src_addr"` // validator redelegation source owner addr
@@ -108,6 +213,67 @@ type Redelegation struct {
SharesDst sdk.Rat `json:"shares_dst"` // amount of destination shares redelegating
}
type redValue struct {
CreationHeight int64
MinTime int64
InitialBalance sdk.Coin
Balance sdk.Coin
SharesSrc sdk.Rat
SharesDst sdk.Rat
}
// return the redelegation without fields contained within the key for the store
func MustMarshalRED(cdc *wire.Codec, red Redelegation) []byte {
val := redValue{
red.CreationHeight,
red.MinTime,
red.InitialBalance,
red.Balance,
red.SharesSrc,
red.SharesDst,
}
return cdc.MustMarshalBinary(val)
}
// unmarshal a redelegation from a store key and value
func MustUnmarshalRED(cdc *wire.Codec, key, value []byte) Redelegation {
red, err := UnmarshalRED(cdc, key, value)
if err != nil {
panic(err)
}
return red
}
// unmarshal a redelegation from a store key and value
func UnmarshalRED(cdc *wire.Codec, key, value []byte) (red Redelegation, err error) {
var storeValue redValue
err = cdc.UnmarshalBinary(value, &storeValue)
if err != nil {
return
}
addrs := key[1:] // remove prefix bytes
if len(addrs) != 3*sdk.AddrLen {
err = errors.New("unexpected key length")
return
}
delAddr := sdk.Address(addrs[:sdk.AddrLen])
valSrcAddr := sdk.Address(addrs[sdk.AddrLen : 2*sdk.AddrLen])
valDstAddr := sdk.Address(addrs[2*sdk.AddrLen:])
return Redelegation{
DelegatorAddr: delAddr,
ValidatorSrcAddr: valSrcAddr,
ValidatorDstAddr: valDstAddr,
CreationHeight: storeValue.CreationHeight,
MinTime: storeValue.MinTime,
InitialBalance: storeValue.InitialBalance,
Balance: storeValue.Balance,
SharesSrc: storeValue.SharesSrc,
SharesDst: storeValue.SharesDst,
}, nil
}
// nolint
func (d Redelegation) Equal(d2 Redelegation) bool {
bz1 := MsgCdc.MustMarshalBinary(&d)
@@ -115,20 +281,25 @@ func (d Redelegation) Equal(d2 Redelegation) bool {
return bytes.Equal(bz1, bz2)
}
//Human Friendly pretty printer
// HumanReadableString returns a human readable string representation of a
// Redelegation. An error is returned if the UnbondingDelegation's delegator or
// validator addresses cannot be Bech32 encoded.
func (d Redelegation) HumanReadableString() (string, error) {
bechAcc, err := sdk.Bech32ifyAcc(d.DelegatorAddr)
if err != nil {
return "", err
}
bechValSrc, err := sdk.Bech32ifyAcc(d.ValidatorSrcAddr)
if err != nil {
return "", err
}
bechValDst, err := sdk.Bech32ifyAcc(d.ValidatorDstAddr)
if err != nil {
return "", err
}
resp := "Redelegation \n"
resp += fmt.Sprintf("Delegator: %s\n", bechAcc)
resp += fmt.Sprintf("Source Validator: %s\n", bechValSrc)
+116
View File
@@ -0,0 +1,116 @@
package types
import (
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
)
func TestDelegationEqual(t *testing.T) {
d1 := Delegation{
DelegatorAddr: addr1,
ValidatorAddr: addr2,
Shares: sdk.NewRat(100),
}
d2 := Delegation{
DelegatorAddr: addr1,
ValidatorAddr: addr2,
Shares: sdk.NewRat(100),
}
ok := d1.Equal(d2)
require.True(t, ok)
d2.ValidatorAddr = addr3
d2.Shares = sdk.NewRat(200)
ok = d1.Equal(d2)
require.False(t, ok)
}
func TestDelegationHumanReadableString(t *testing.T) {
d := Delegation{
DelegatorAddr: addr1,
ValidatorAddr: addr2,
Shares: sdk.NewRat(100),
}
// NOTE: Being that the validator's keypair is random, we cannot test the
// actual contents of the string.
valStr, err := d.HumanReadableString()
require.Nil(t, err)
require.NotEmpty(t, valStr)
}
func TestUnbondingDelegationEqual(t *testing.T) {
ud1 := UnbondingDelegation{
DelegatorAddr: addr1,
ValidatorAddr: addr2,
}
ud2 := UnbondingDelegation{
DelegatorAddr: addr1,
ValidatorAddr: addr2,
}
ok := ud1.Equal(ud2)
require.True(t, ok)
ud2.ValidatorAddr = addr3
ud2.MinTime = 20 * 20 * 2
ok = ud1.Equal(ud2)
require.False(t, ok)
}
func TestUnbondingDelegationHumanReadableString(t *testing.T) {
ud := UnbondingDelegation{
DelegatorAddr: addr1,
ValidatorAddr: addr2,
}
// NOTE: Being that the validator's keypair is random, we cannot test the
// actual contents of the string.
valStr, err := ud.HumanReadableString()
require.Nil(t, err)
require.NotEmpty(t, valStr)
}
func TestRedelegationEqual(t *testing.T) {
r1 := Redelegation{
DelegatorAddr: addr1,
ValidatorSrcAddr: addr2,
ValidatorDstAddr: addr3,
}
r2 := Redelegation{
DelegatorAddr: addr1,
ValidatorSrcAddr: addr2,
ValidatorDstAddr: addr3,
}
ok := r1.Equal(r2)
require.True(t, ok)
r2.SharesDst = sdk.NewRat(10)
r2.SharesSrc = sdk.NewRat(20)
r2.MinTime = 20 * 20 * 2
ok = r1.Equal(r2)
require.False(t, ok)
}
func TestRedelegationHumanReadableString(t *testing.T) {
r := Redelegation{
DelegatorAddr: addr1,
ValidatorSrcAddr: addr2,
ValidatorDstAddr: addr3,
SharesDst: sdk.NewRat(10),
SharesSrc: sdk.NewRat(20),
}
// NOTE: Being that the validator's keypair is random, we cannot test the
// actual contents of the string.
valStr, err := r.HumanReadableString()
require.Nil(t, err)
require.NotEmpty(t, valStr)
}
+24 -3
View File
@@ -25,97 +25,118 @@ const (
func ErrNilValidatorAddr(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidInput, "validator address is nil")
}
func ErrNoValidatorFound(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidValidator, "validator does not exist for that address")
}
func ErrValidatorAlreadyExists(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidValidator, "validator already exist, cannot re-create validator")
}
func ErrValidatorRevoked(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidValidator, "validator for this address is currently revoked")
}
func ErrBadRemoveValidator(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidValidator, "error removing validator")
}
func ErrDescriptionLength(codespace sdk.CodespaceType, descriptor string, got, max int) sdk.Error {
msg := fmt.Sprintf("bad description length for %v, got length %v, max is %v", descriptor, got, max)
return sdk.NewError(codespace, CodeInvalidValidator, msg)
}
func ErrCommissionNegative(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidValidator, "commission must be positive")
}
func ErrCommissionHuge(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidValidator, "commission cannot be more than 100%")
}
// delegation
func ErrNilDelegatorAddr(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidInput, "delegator address is nil")
}
func ErrBadDenom(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "invalid coin denomination")
}
func ErrBadDelegationAmount(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "amount must be > 0")
}
func ErrNoDelegation(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "no delegation for this (address, validator) pair")
}
func ErrBadDelegatorAddr(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "delegator does not exist for that address")
}
func ErrNoDelegatorForAddress(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "delegator does not contain this delegation")
}
func ErrInsufficientShares(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "insufficient delegation shares")
}
func ErrDelegationValidatorEmpty(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "cannot delegate to an empty validator")
}
func ErrNotEnoughDelegationShares(codespace sdk.CodespaceType, shares string) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, fmt.Sprintf("not enough shares only have %v", shares))
}
func ErrBadSharesAmount(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "shares must be > 0")
}
func ErrBadSharesPrecision(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation,
fmt.Sprintf("shares denominator must be < %s, try reducing the number of decimal points",
maximumBondingRationalDenominator.String()),
)
}
func ErrBadSharesPercent(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "shares percent must be >0 and <=1")
}
// redelegation
func ErrNotMature(codespace sdk.CodespaceType, operation, descriptor string, got, min int64) sdk.Error {
msg := fmt.Sprintf("%v is not mature requires a min %v of %v, currently it is %v",
operation, descriptor, got, min)
return sdk.NewError(codespace, CodeUnauthorized, msg)
}
func ErrNoUnbondingDelegation(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "no unbonding delegation found")
}
func ErrNoRedelegation(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "no redelegation found")
}
func ErrBadRedelegationDst(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "redelegation validator not found")
}
func ErrTransitiveRedelegation(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation,
"redelegation to this validator already in progress, first redelegation to this validator must complete before next redelegation")
}
// messages
func ErrBothShareMsgsGiven(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidInput, "both shares amount and shares percent provided")
}
func ErrNeitherShareMsgsGiven(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidInput, "neither shares amount nor shares percent provided")
}
func ErrMissingSignature(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidValidator, "missing signature")
}
+7 -7
View File
@@ -63,7 +63,7 @@ func (msg MsgCreateValidator) GetSignBytes() []byte {
if err != nil {
panic(err)
}
return b
return sdk.MustSortJSON(b)
}
// quick validity check
@@ -114,7 +114,7 @@ func (msg MsgEditValidator) GetSignBytes() []byte {
if err != nil {
panic(err)
}
return b
return sdk.MustSortJSON(b)
}
// quick validity check
@@ -166,7 +166,7 @@ func (msg MsgDelegate) GetSignBytes() []byte {
if err != nil {
panic(err)
}
return b
return sdk.MustSortJSON(b)
}
// quick validity check
@@ -226,7 +226,7 @@ func (msg MsgBeginRedelegate) GetSignBytes() []byte {
if err != nil {
panic(err)
}
return b
return sdk.MustSortJSON(b)
}
// quick validity check
@@ -286,7 +286,7 @@ func (msg MsgCompleteRedelegate) GetSignBytes() []byte {
if err != nil {
panic(err)
}
return b
return sdk.MustSortJSON(b)
}
// quick validity check
@@ -338,7 +338,7 @@ func (msg MsgBeginUnbonding) GetSignBytes() []byte {
if err != nil {
panic(err)
}
return b
return sdk.MustSortJSON(b)
}
// quick validity check
@@ -387,7 +387,7 @@ func (msg MsgCompleteUnbonding) GetSignBytes() []byte {
if err != nil {
panic(err)
}
return b
return sdk.MustSortJSON(b)
}
// quick validity check
+3 -29
View File
@@ -10,9 +10,9 @@ import (
)
var (
coinPos = sdk.Coin{"steak", sdk.NewInt(1000)}
coinZero = sdk.Coin{"steak", sdk.NewInt(0)}
coinNeg = sdk.Coin{"steak", sdk.NewInt(-10000)}
coinPos = sdk.NewCoin("steak", 1000)
coinZero = sdk.NewCoin("steak", 0)
coinNeg = sdk.NewCoin("steak", -10000)
)
// test ValidateBasic for MsgCreateValidator
@@ -197,29 +197,3 @@ func TestMsgCompleteUnbonding(t *testing.T) {
}
}
}
// TODO introduce with go-amino
//func TestSerializeMsg(t *testing.T) {
//// make sure all types construct properly
//bondAmt := 1234321
//bond := sdk.Coin{Denom: "atom", Amount: int64(bondAmt)}
//tests := []struct {
//tx sdk.Msg
//}{
//{NewMsgCreateValidator(addr1, pk1, bond, Description{})},
//{NewMsgEditValidator(addr1, Description{})},
//{NewMsgDelegate(addr1, addr2, bond)},
//{NewMsgUnbond(addr1, addr2, strconv.Itoa(bondAmt))},
//}
//for i, tc := range tests {
//var tx sdk.Tx
//bs := wire.BinaryBytes(tc.tx)
//err := wire.ReadBinaryBytes(bs, &tx)
//if require.NoError(t, err, "%d", i) {
//require.Equal(t, tc.tx, tx, "%d", i)
//}
//}
//}
+7 -3
View File
@@ -6,6 +6,10 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// defaultUnbondingTime reflects three weeks in seconds as the default
// unbonding time.
const defaultUnbondingTime int64 = 60 * 60 * 24 * 3
// Params defines the high level settings for staking
type Params struct {
InflationRateChange sdk.Rat `json:"inflation_rate_change"` // maximum annual change in inflation rate
@@ -19,21 +23,21 @@ type Params struct {
BondDenom string `json:"bond_denom"` // bondable coin denomination
}
// nolint
// Equal returns a boolean determining if two Param types are identical.
func (p Params) Equal(p2 Params) bool {
bz1 := MsgCdc.MustMarshalBinary(&p)
bz2 := MsgCdc.MustMarshalBinary(&p2)
return bytes.Equal(bz1, bz2)
}
// default params
// DefaultParams returns a default set of parameters.
func DefaultParams() Params {
return Params{
InflationRateChange: sdk.NewRat(13, 100),
InflationMax: sdk.NewRat(20, 100),
InflationMin: sdk.NewRat(7, 100),
GoalBonded: sdk.NewRat(67, 100),
UnbondingTime: 60 * 60 * 24 * 3, // 3 weeks in seconds
UnbondingTime: defaultUnbondingTime,
MaxValidators: 100,
BondDenom: "steak",
}
+21
View File
@@ -0,0 +1,21 @@
package types
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestParamsEqual(t *testing.T) {
p1 := DefaultParams()
p2 := DefaultParams()
ok := p1.Equal(p2)
require.True(t, ok)
p2.UnbondingTime = 60 * 60 * 24 * 2
p2.BondDenom = "soup"
ok = p1.Equal(p2)
require.False(t, ok)
}
+19 -6
View File
@@ -3,11 +3,24 @@ package types
import (
"testing"
"github.com/stretchr/testify/require"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
)
func TestPoolEqual(t *testing.T) {
p1 := InitialPool()
p2 := InitialPool()
ok := p1.Equal(p2)
require.True(t, ok)
p2.BondedTokens = 3
p2.BondedShares = sdk.NewRat(10)
ok = p1.Equal(p2)
require.False(t, ok)
}
func TestBondedRatio(t *testing.T) {
pool := InitialPool()
pool.LooseTokens = 1
@@ -62,10 +75,10 @@ func TestUnbondedShareExRate(t *testing.T) {
}
func TestAddTokensBonded(t *testing.T) {
poolA := InitialPool()
poolA.LooseTokens = 10
require.Equal(t, poolA.BondedShareExRate(), sdk.OneRat())
poolB, sharesB := poolA.addTokensBonded(10)
require.Equal(t, poolB.BondedShareExRate(), sdk.OneRat())
@@ -78,10 +91,10 @@ func TestAddTokensBonded(t *testing.T) {
}
func TestRemoveSharesBonded(t *testing.T) {
poolA := InitialPool()
poolA.LooseTokens = 10
require.Equal(t, poolA.BondedShareExRate(), sdk.OneRat())
poolB, tokensB := poolA.removeSharesBonded(sdk.NewRat(10))
require.Equal(t, poolB.BondedShareExRate(), sdk.OneRat())
@@ -94,10 +107,10 @@ func TestRemoveSharesBonded(t *testing.T) {
}
func TestAddTokensUnbonded(t *testing.T) {
poolA := InitialPool()
poolA.LooseTokens = 10
require.Equal(t, poolA.UnbondedShareExRate(), sdk.OneRat())
poolB, sharesB := poolA.addTokensUnbonded(10)
require.Equal(t, poolB.UnbondedShareExRate(), sdk.OneRat())
@@ -110,11 +123,11 @@ func TestAddTokensUnbonded(t *testing.T) {
}
func TestRemoveSharesUnbonded(t *testing.T) {
poolA := InitialPool()
poolA.UnbondedTokens = 10
poolA.UnbondedShares = sdk.NewRat(10)
require.Equal(t, poolA.UnbondedShareExRate(), sdk.OneRat())
poolB, tokensB := poolA.removeSharesUnbonded(sdk.NewRat(10))
require.Equal(t, poolB.UnbondedShareExRate(), sdk.OneRat())
+48 -30
View File
@@ -4,18 +4,19 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// pool shares held by a validator
// PoolShares reflects the shares of a validator in a pool.
type PoolShares struct {
Status sdk.BondStatus `json:"status"`
Amount sdk.Rat `json:"amount"` // total shares of type ShareKind
Amount sdk.Rat `json:"amount"`
}
// only the vitals - does not check bond height of IntraTxCounter
// Equal returns a boolean determining of two PoolShares are identical.
func (s PoolShares) Equal(s2 PoolShares) bool {
return s.Status == s2.Status &&
s.Amount.Equal(s2.Amount)
}
// NewUnbondedShares returns a new PoolShares with a specified unbonded amount.
func NewUnbondedShares(amount sdk.Rat) PoolShares {
return PoolShares{
Status: sdk.Unbonded,
@@ -23,6 +24,8 @@ func NewUnbondedShares(amount sdk.Rat) PoolShares {
}
}
// NewUnbondingShares returns a new PoolShares with a specified unbonding
// amount.
func NewUnbondingShares(amount sdk.Rat) PoolShares {
return PoolShares{
Status: sdk.Unbonding,
@@ -30,6 +33,7 @@ func NewUnbondingShares(amount sdk.Rat) PoolShares {
}
}
// NewBondedShares returns a new PoolSahres with a specified bonding amount.
func NewBondedShares(amount sdk.Rat) PoolShares {
return PoolShares{
Status: sdk.Bonded,
@@ -37,9 +41,7 @@ func NewBondedShares(amount sdk.Rat) PoolShares {
}
}
//_________________________________________________________________________________________________________
// amount of unbonded shares
// Unbonded returns the amount of unbonded shares.
func (s PoolShares) Unbonded() sdk.Rat {
if s.Status == sdk.Unbonded {
return s.Amount
@@ -47,7 +49,7 @@ func (s PoolShares) Unbonded() sdk.Rat {
return sdk.ZeroRat()
}
// amount of unbonding shares
// Unbonding returns the amount of unbonding shares.
func (s PoolShares) Unbonding() sdk.Rat {
if s.Status == sdk.Unbonding {
return s.Amount
@@ -55,7 +57,7 @@ func (s PoolShares) Unbonding() sdk.Rat {
return sdk.ZeroRat()
}
// amount of bonded shares
// Bonded returns amount of bonded shares.
func (s PoolShares) Bonded() sdk.Rat {
if s.Status == sdk.Bonded {
return s.Amount
@@ -63,64 +65,80 @@ func (s PoolShares) Bonded() sdk.Rat {
return sdk.ZeroRat()
}
//_________________________________________________________________________________________________________
// equivalent amount of shares if the shares were unbonded
// ToUnbonded returns the equivalent amount of pool shares if the shares were
// unbonded.
func (s PoolShares) ToUnbonded(p Pool) PoolShares {
var amount sdk.Rat
switch s.Status {
case sdk.Bonded:
exRate := p.BondedShareExRate().Quo(p.UnbondedShareExRate()) // (tok/bondedshr)/(tok/unbondedshr) = unbondedshr/bondedshr
amount = s.Amount.Mul(exRate) // bondedshr*unbondedshr/bondedshr = unbondedshr
// (tok/bondedshr)/(tok/unbondedshr) = unbondedshr/bondedshr
exRate := p.BondedShareExRate().Quo(p.UnbondedShareExRate())
// bondedshr*unbondedshr/bondedshr = unbondedshr
amount = s.Amount.Mul(exRate)
case sdk.Unbonding:
exRate := p.UnbondingShareExRate().Quo(p.UnbondedShareExRate()) // (tok/unbondingshr)/(tok/unbondedshr) = unbondedshr/unbondingshr
amount = s.Amount.Mul(exRate) // unbondingshr*unbondedshr/unbondingshr = unbondedshr
// (tok/unbondingshr)/(tok/unbondedshr) = unbondedshr/unbondingshr
exRate := p.UnbondingShareExRate().Quo(p.UnbondedShareExRate())
// unbondingshr*unbondedshr/unbondingshr = unbondedshr
amount = s.Amount.Mul(exRate)
case sdk.Unbonded:
amount = s.Amount
}
return NewUnbondedShares(amount)
}
// equivalent amount of shares if the shares were unbonding
// ToUnbonding returns the equivalent amount of pool shares if the shares were
// unbonding.
func (s PoolShares) ToUnbonding(p Pool) PoolShares {
var amount sdk.Rat
switch s.Status {
case sdk.Bonded:
exRate := p.BondedShareExRate().Quo(p.UnbondingShareExRate()) // (tok/bondedshr)/(tok/unbondingshr) = unbondingshr/bondedshr
amount = s.Amount.Mul(exRate) // bondedshr*unbondingshr/bondedshr = unbondingshr
// (tok/bondedshr)/(tok/unbondingshr) = unbondingshr/bondedshr
exRate := p.BondedShareExRate().Quo(p.UnbondingShareExRate())
// bondedshr*unbondingshr/bondedshr = unbondingshr
amount = s.Amount.Mul(exRate)
case sdk.Unbonding:
amount = s.Amount
case sdk.Unbonded:
exRate := p.UnbondedShareExRate().Quo(p.UnbondingShareExRate()) // (tok/unbondedshr)/(tok/unbondingshr) = unbondingshr/unbondedshr
amount = s.Amount.Mul(exRate) // unbondedshr*unbondingshr/unbondedshr = unbondingshr
// (tok/unbondedshr)/(tok/unbondingshr) = unbondingshr/unbondedshr
exRate := p.UnbondedShareExRate().Quo(p.UnbondingShareExRate())
// unbondedshr*unbondingshr/unbondedshr = unbondingshr
amount = s.Amount.Mul(exRate)
}
return NewUnbondingShares(amount)
}
// equivalent amount of shares if the shares were bonded
// ToBonded the equivalent amount of pool shares if the shares were bonded.
func (s PoolShares) ToBonded(p Pool) PoolShares {
var amount sdk.Rat
switch s.Status {
case sdk.Bonded:
amount = s.Amount
case sdk.Unbonding:
exRate := p.UnbondingShareExRate().Quo(p.BondedShareExRate()) // (tok/ubshr)/(tok/bshr) = bshr/ubshr
amount = s.Amount.Mul(exRate) // ubshr*bshr/ubshr = bshr
// (tok/ubshr)/(tok/bshr) = bshr/ubshr
exRate := p.UnbondingShareExRate().Quo(p.BondedShareExRate())
// ubshr*bshr/ubshr = bshr
amount = s.Amount.Mul(exRate)
case sdk.Unbonded:
exRate := p.UnbondedShareExRate().Quo(p.BondedShareExRate()) // (tok/ubshr)/(tok/bshr) = bshr/ubshr
amount = s.Amount.Mul(exRate) // ubshr*bshr/ubshr = bshr
// (tok/ubshr)/(tok/bshr) = bshr/ubshr
exRate := p.UnbondedShareExRate().Quo(p.BondedShareExRate())
// ubshr*bshr/ubshr = bshr
amount = s.Amount.Mul(exRate)
}
return NewUnbondedShares(amount)
}
//_________________________________________________________________________________________________________
// TODO better tests
// get the equivalent amount of tokens contained by the shares
// Tokens returns the equivalent amount of tokens contained by the pool shares
// for a given pool.
func (s PoolShares) Tokens(p Pool) sdk.Rat {
switch s.Status {
case sdk.Bonded:
return p.BondedShareExRate().Mul(s.Amount) // (tokens/shares) * shares
return p.BondedShareExRate().Mul(s.Amount)
case sdk.Unbonding:
return p.UnbondingShareExRate().Mul(s.Amount)
case sdk.Unbonded:
+35
View File
@@ -0,0 +1,35 @@
package types
import (
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
)
func TestPoolSharesTokens(t *testing.T) {
pool := InitialPool()
pool.LooseTokens = 10
val := Validator{
Owner: addr1,
PubKey: pk1,
PoolShares: NewBondedShares(sdk.NewRat(100)),
DelegatorShares: sdk.NewRat(100),
}
pool.BondedTokens = val.PoolShares.Bonded().RoundInt64()
pool.BondedShares = val.PoolShares.Bonded()
poolShares := NewBondedShares(sdk.NewRat(50))
tokens := poolShares.Tokens(pool)
require.Equal(t, int64(50), tokens.RoundInt64())
poolShares = NewUnbondingShares(sdk.NewRat(50))
tokens = poolShares.Tokens(pool)
require.Equal(t, int64(50), tokens.RoundInt64())
poolShares = NewUnbondedShares(sdk.NewRat(50))
tokens = poolShares.Tokens(pool)
require.Equal(t, int64(50), tokens.RoundInt64())
}
@@ -11,7 +11,6 @@ import (
)
var (
// dummy pubkeys/addresses
pk1 = crypto.GenPrivKeyEd25519().PubKey()
pk2 = crypto.GenPrivKeyEd25519().PubKey()
pk3 = crypto.GenPrivKeyEd25519().PubKey()
@@ -23,18 +22,20 @@ var (
emptyPubkey crypto.PubKey
)
//______________________________________________________________
// any operation that transforms staking state
// takes in RNG instance, pool, validator
// returns updated pool, updated validator, delta tokens, descriptive message
// Operation reflects any operation that transforms staking state. It takes in
// a RNG instance, pool, validator and returns an updated pool, updated
// validator, delta tokens, and descriptive message.
type Operation func(r *rand.Rand, pool Pool, c Validator) (Pool, Validator, int64, string)
// operation: bond or unbond a validator depending on current status
// OpBondOrUnbond implements an operation that bonds or unbonds a validator
// depending on current status.
// nolint: unparam
func OpBondOrUnbond(r *rand.Rand, pool Pool, val Validator) (Pool, Validator, int64, string) {
var msg string
var newStatus sdk.BondStatus
var (
msg string
newStatus sdk.BondStatus
)
if val.Status() == sdk.Bonded {
msg = fmt.Sprintf("sdk.Unbonded previously bonded validator %s (poolShares: %v, delShares: %v, DelegatorShareExRate: %v)",
val.Owner, val.PoolShares.Bonded(), val.DelegatorShares, val.DelegatorShareExRate(pool))
@@ -45,21 +46,27 @@ func OpBondOrUnbond(r *rand.Rand, pool Pool, val Validator) (Pool, Validator, in
val.Owner, val.PoolShares.Bonded(), val.DelegatorShares, val.DelegatorShareExRate(pool))
newStatus = sdk.Bonded
}
val, pool = val.UpdateStatus(pool, newStatus)
return pool, val, 0, msg
}
// operation: add a random number of tokens to a validator
// OpAddTokens implements an operation that adds a random number of tokens to a
// validator.
func OpAddTokens(r *rand.Rand, pool Pool, val Validator) (Pool, Validator, int64, string) {
tokens := int64(r.Int31n(1000))
msg := fmt.Sprintf("validator %s (status: %d, poolShares: %v, delShares: %v, DelegatorShareExRate: %v)",
val.Owner, val.Status(), val.PoolShares.Bonded(), val.DelegatorShares, val.DelegatorShareExRate(pool))
tokens := int64(r.Int31n(1000))
val, pool, _ = val.AddTokensFromDel(pool, tokens)
msg = fmt.Sprintf("Added %d tokens to %s", tokens, msg)
return pool, val, -1 * tokens, msg // tokens are removed so for accounting must be negative
// Tokens are removed so for accounting must be negative
return pool, val, -1 * tokens, msg
}
// operation: remove a random number of shares from a validator
// OpRemoveShares implements an operation that removes a random number of
// shares from a validator.
func OpRemoveShares(r *rand.Rand, pool Pool, val Validator) (Pool, Validator, int64, string) {
var shares sdk.Rat
for {
@@ -76,7 +83,7 @@ func OpRemoveShares(r *rand.Rand, pool Pool, val Validator) (Pool, Validator, in
return pool, val, tokens, msg
}
// pick a random staking operation
// RandomOperation returns a random staking operation.
func RandomOperation(r *rand.Rand) Operation {
operations := []Operation{
OpBondOrUnbond,
@@ -86,10 +93,11 @@ func RandomOperation(r *rand.Rand) Operation {
r.Shuffle(len(operations), func(i, j int) {
operations[i], operations[j] = operations[j], operations[i]
})
return operations[0]
}
// ensure invariants that should always be true are true
// AssertInvariants ensures invariants that should always be true are true.
// nolint: unparam
func AssertInvariants(t *testing.T, msg string,
pOrig Pool, cOrig []Validator, pMod Pool, vMods []Validator, tokens int64) {
@@ -105,29 +113,28 @@ func AssertInvariants(t *testing.T, msg string,
pOrig.UnbondedTokens, pOrig.BondedTokens,
pMod.UnbondedTokens, pMod.BondedTokens, tokens)
// nonnegative bonded shares
// Nonnegative bonded shares
require.False(t, pMod.BondedShares.LT(sdk.ZeroRat()),
"Negative bonded shares - msg: %v\npOrig: %v\npMod: %v\ntokens: %v\n",
msg, pOrig, pMod, tokens)
// nonnegative unbonded shares
// Nonnegative unbonded shares
require.False(t, pMod.UnbondedShares.LT(sdk.ZeroRat()),
"Negative unbonded shares - msg: %v\npOrig: %v\npMod: %v\ntokens: %v\n",
msg, pOrig, pMod, tokens)
// nonnegative bonded ex rate
// Nonnegative bonded ex rate
require.False(t, pMod.BondedShareExRate().LT(sdk.ZeroRat()),
"Applying operation \"%s\" resulted in negative BondedShareExRate: %d",
msg, pMod.BondedShareExRate().RoundInt64())
// nonnegative unbonded ex rate
// Nonnegative unbonded ex rate
require.False(t, pMod.UnbondedShareExRate().LT(sdk.ZeroRat()),
"Applying operation \"%s\" resulted in negative UnbondedShareExRate: %d",
msg, pMod.UnbondedShareExRate().RoundInt64())
for _, vMod := range vMods {
// nonnegative ex rate
// Nonnegative ex rate
require.False(t, vMod.DelegatorShareExRate(pMod).LT(sdk.ZeroRat()),
"Applying operation \"%s\" resulted in negative validator.DelegatorShareExRate(): %v (validator.Owner: %s)",
msg,
@@ -135,7 +142,7 @@ func AssertInvariants(t *testing.T, msg string,
vMod.Owner,
)
// nonnegative poolShares
// Nonnegative poolShares
require.False(t, vMod.PoolShares.Bonded().LT(sdk.ZeroRat()),
"Applying operation \"%s\" resulted in negative validator.PoolShares.Bonded(): %v (validator.DelegatorShares: %v, validator.DelegatorShareExRate: %v, validator.Owner: %s)",
msg,
@@ -145,7 +152,7 @@ func AssertInvariants(t *testing.T, msg string,
vMod.Owner,
)
// nonnegative delShares
// Nonnegative delShares
require.False(t, vMod.DelegatorShares.LT(sdk.ZeroRat()),
"Applying operation \"%s\" resulted in negative validator.DelegatorShares: %v (validator.PoolShares.Bonded(): %v, validator.DelegatorShareExRate: %v, validator.Owner: %s)",
msg,
@@ -154,27 +161,25 @@ func AssertInvariants(t *testing.T, msg string,
vMod.DelegatorShareExRate(pMod),
vMod.Owner,
)
}
}
//________________________________________________________________________________
// TODO refactor this random setup
// TODO: refactor this random setup
// generate a random validator
// randomValidator generates a random validator.
// nolint: unparam
func randomValidator(r *rand.Rand, i int) Validator {
poolSharesAmt := sdk.NewRat(int64(r.Int31n(10000)))
delShares := sdk.NewRat(int64(r.Int31n(10000)))
var pShares PoolShares
if r.Float64() < float64(0.5) {
pShares = NewBondedShares(poolSharesAmt)
} else {
pShares = NewUnbondedShares(poolSharesAmt)
}
return Validator{
Owner: addr1,
PubKey: pk1,
@@ -183,7 +188,7 @@ func randomValidator(r *rand.Rand, i int) Validator {
}
}
// generate a random staking state
// RandomSetup generates a random staking state.
func RandomSetup(r *rand.Rand, numValidators int) (Pool, []Validator) {
pool := InitialPool()
pool.LooseTokens = 100000
@@ -191,6 +196,7 @@ func RandomSetup(r *rand.Rand, numValidators int) (Pool, []Validator) {
validators := make([]Validator, numValidators)
for i := 0; i < numValidators; i++ {
validator := randomValidator(r, i)
if validator.Status() == sdk.Bonded {
pool.BondedShares = pool.BondedShares.Add(validator.PoolShares.Bonded())
pool.BondedTokens += validator.PoolShares.Bonded().RoundInt64()
@@ -198,7 +204,9 @@ func RandomSetup(r *rand.Rand, numValidators int) (Pool, []Validator) {
pool.UnbondedShares = pool.UnbondedShares.Add(validator.PoolShares.Unbonded())
pool.UnbondedTokens += validator.PoolShares.Unbonded().RoundInt64()
}
validators[i] = validator
}
return pool, validators
}
+137 -36
View File
@@ -2,6 +2,7 @@ package types
import (
"bytes"
"errors"
"fmt"
abci "github.com/tendermint/tendermint/abci/types"
@@ -9,8 +10,11 @@ import (
tmtypes "github.com/tendermint/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
)
const doNotModifyDescVal = "[do-not-modify]"
// Validator defines the total amount of bond shares and their exchange rate to
// coins. Accumulation of interest is modelled as an in increase in the
// exchange rate, and slashing as a decrease. When coins are delegated to this
@@ -60,6 +64,84 @@ func NewValidator(owner sdk.Address, pubKey crypto.PubKey, description Descripti
}
}
// what's kept in the store value
type validatorValue struct {
PubKey crypto.PubKey
Revoked bool
PoolShares PoolShares
DelegatorShares sdk.Rat
Description Description
BondHeight int64
BondIntraTxCounter int16
ProposerRewardPool sdk.Coins
Commission sdk.Rat
CommissionMax sdk.Rat
CommissionChangeRate sdk.Rat
CommissionChangeToday sdk.Rat
PrevBondedShares sdk.Rat
}
// return the redelegation without fields contained within the key for the store
func MustMarshalValidator(cdc *wire.Codec, validator Validator) []byte {
val := validatorValue{
PubKey: validator.PubKey,
Revoked: validator.Revoked,
PoolShares: validator.PoolShares,
DelegatorShares: validator.DelegatorShares,
Description: validator.Description,
BondHeight: validator.BondHeight,
BondIntraTxCounter: validator.BondIntraTxCounter,
ProposerRewardPool: validator.ProposerRewardPool,
Commission: validator.Commission,
CommissionMax: validator.CommissionMax,
CommissionChangeRate: validator.CommissionChangeRate,
CommissionChangeToday: validator.CommissionChangeToday,
PrevBondedShares: validator.PrevBondedShares,
}
return cdc.MustMarshalBinary(val)
}
// unmarshal a redelegation from a store key and value
func MustUnmarshalValidator(cdc *wire.Codec, ownerAddr, value []byte) Validator {
validator, err := UnmarshalValidator(cdc, ownerAddr, value)
if err != nil {
panic(err)
}
return validator
}
// unmarshal a redelegation from a store key and value
func UnmarshalValidator(cdc *wire.Codec, ownerAddr, value []byte) (validator Validator, err error) {
var storeValue validatorValue
err = cdc.UnmarshalBinary(value, &storeValue)
if err != nil {
return
}
if len(ownerAddr) != 20 {
err = errors.New("unexpected address length")
return
}
return Validator{
Owner: ownerAddr,
PubKey: storeValue.PubKey,
Revoked: storeValue.Revoked,
PoolShares: storeValue.PoolShares,
DelegatorShares: storeValue.DelegatorShares,
Description: storeValue.Description,
BondHeight: storeValue.BondHeight,
BondIntraTxCounter: storeValue.BondIntraTxCounter,
ProposerRewardPool: storeValue.ProposerRewardPool,
Commission: storeValue.Commission,
CommissionMax: storeValue.CommissionMax,
CommissionChangeRate: storeValue.CommissionChangeRate,
CommissionChangeToday: storeValue.CommissionChangeToday,
PrevBondedShares: storeValue.PrevBondedShares,
}, nil
}
// only the vitals - does not check bond height of IntraTxCounter
func (v Validator) Equal(c2 Validator) bool {
return v.PubKey.Equals(c2.PubKey) &&
@@ -67,8 +149,6 @@ func (v Validator) Equal(c2 Validator) bool {
v.PoolShares.Equal(c2.PoolShares) &&
v.DelegatorShares.Equal(c2.DelegatorShares) &&
v.Description == c2.Description &&
//v.BondHeight == c2.BondHeight &&
//v.BondIntraTxCounter == c2.BondIntraTxCounter && // counter is always changing
v.ProposerRewardPool.IsEqual(c2.ProposerRewardPool) &&
v.Commission.Equal(c2.Commission) &&
v.CommissionMax.Equal(c2.CommissionMax) &&
@@ -85,6 +165,7 @@ type Description struct {
Details string `json:"details"` // optional details
}
// NewDescription returns a new Description with the provided values.
func NewDescription(moniker, identity, website, details string) Description {
return Description{
Moniker: moniker,
@@ -94,20 +175,22 @@ func NewDescription(moniker, identity, website, details string) Description {
}
}
// update the description based on input
// UpdateDescription updates the fields of a given description. An error is
// returned if the resulting description contains an invalid length.
func (d Description) UpdateDescription(d2 Description) (Description, sdk.Error) {
if d.Moniker == "[do-not-modify]" {
if d.Moniker == doNotModifyDescVal {
d2.Moniker = d.Moniker
}
if d.Identity == "[do-not-modify]" {
if d.Identity == doNotModifyDescVal {
d2.Identity = d.Identity
}
if d.Website == "[do-not-modify]" {
if d.Website == doNotModifyDescVal {
d2.Website = d.Website
}
if d.Details == "[do-not-modify]" {
if d.Details == doNotModifyDescVal {
d2.Details = d.Details
}
return Description{
Moniker: d2.Moniker,
Identity: d2.Identity,
@@ -116,7 +199,7 @@ func (d Description) UpdateDescription(d2 Description) (Description, sdk.Error)
}.EnsureLength()
}
// ensure the length of the description
// EnsureLength ensures the length of a validator's description.
func (d Description) EnsureLength() (Description, sdk.Error) {
if len(d.Moniker) > 70 {
return d, ErrDescriptionLength(DefaultCodespace, "moniker", len(d.Moniker), 70)
@@ -130,10 +213,11 @@ func (d Description) EnsureLength() (Description, sdk.Error) {
if len(d.Details) > 280 {
return d, ErrDescriptionLength(DefaultCodespace, "details", len(d.Details), 280)
}
return d, nil
}
// abci validator from stake validator type
// ABCIValidator returns an abci.Validator from a staked validator type.
func (v Validator) ABCIValidator() abci.Validator {
return abci.Validator{
PubKey: tmtypes.TM2PB.PubKey(v.PubKey),
@@ -141,8 +225,8 @@ func (v Validator) ABCIValidator() abci.Validator {
}
}
// abci validator from stake validator type
// with zero power used for validator updates
// ABCIValidatorZero returns an abci.Validator from a staked validator type
// with with zero power used for validator updates.
func (v Validator) ABCIValidatorZero() abci.Validator {
return abci.Validator{
PubKey: tmtypes.TM2PB.PubKey(v.PubKey),
@@ -150,12 +234,13 @@ func (v Validator) ABCIValidatorZero() abci.Validator {
}
}
// abci validator from stake validator type
// Status returns the validator's bond status inferred from the pool shares.
func (v Validator) Status() sdk.BondStatus {
return v.PoolShares.Status
}
// update the location of the shares within a validator if its bond status has changed
// UpdateStatus updates the location of the shares within a validator if it's
// bond status has changed.
func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, Pool) {
var tokens int64
@@ -173,7 +258,8 @@ func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator,
pool, tokens = pool.removeSharesUnbonding(v.PoolShares.Amount)
case sdk.Bonded:
if NewStatus == sdk.Bonded { // return if nothing needs switching
if NewStatus == sdk.Bonded {
// Return if nothing needs switching
return v, pool
}
pool, tokens = pool.removeSharesBonded(v.PoolShares.Amount)
@@ -187,14 +273,16 @@ func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator,
case sdk.Bonded:
pool, v.PoolShares = pool.addTokensBonded(tokens)
}
return v, pool
}
// Remove pool shares
// Returns corresponding tokens, which could be burned (e.g. when slashing
// a validator) or redistributed elsewhere
// RemovePoolShares removes pool shares from a validator. It returns
// corresponding tokens, which could be burned (e.g. when slashing a validator)
// or redistributed elsewhere.
func (v Validator) RemovePoolShares(pool Pool, poolShares sdk.Rat) (Validator, Pool, int64) {
var tokens int64
switch v.Status() {
case sdk.Unbonded:
pool, tokens = pool.removeSharesUnbonded(poolShares)
@@ -203,29 +291,33 @@ func (v Validator) RemovePoolShares(pool Pool, poolShares sdk.Rat) (Validator, P
case sdk.Bonded:
pool, tokens = pool.removeSharesBonded(poolShares)
}
v.PoolShares.Amount = v.PoolShares.Amount.Sub(poolShares)
return v, pool, tokens
}
// TODO remove should only be tokens
// get the power or potential power for a validator
// if bonded, the power is the BondedShares
// if not bonded, the power is the amount of bonded shares which the
// the validator would have it was bonded
// EquivalentBondedShares ...
//
// TODO: Remove should only be tokens get the power or potential power for a
// validator if bonded, the power is the BondedShares if not bonded, the power
// is the amount of bonded shares which the the validator would have it was
// bonded.
func (v Validator) EquivalentBondedShares(pool Pool) (eqBondedShares sdk.Rat) {
return v.PoolShares.ToBonded(pool).Amount
}
//_________________________________________________________________________________________________________
// add tokens to a validator
func (v Validator) AddTokensFromDel(pool Pool,
amount int64) (validator2 Validator, p2 Pool, issuedDelegatorShares sdk.Rat) {
// AddTokensFromDel adds tokens to a validator
func (v Validator) AddTokensFromDel(pool Pool, amount int64) (Validator, Pool, sdk.Rat) {
var (
poolShares PoolShares
equivalentBondedShares sdk.Rat
)
exRate := v.DelegatorShareExRate(pool) // bshr/delshr
// bondedShare/delegatedShare
exRate := v.DelegatorShareExRate(pool)
var poolShares PoolShares
var equivalentBondedShares sdk.Rat
switch v.Status() {
case sdk.Unbonded:
pool, poolShares = pool.addTokensUnbonded(amount)
@@ -237,21 +329,24 @@ func (v Validator) AddTokensFromDel(pool Pool,
v.PoolShares.Amount = v.PoolShares.Amount.Add(poolShares.Amount)
equivalentBondedShares = poolShares.ToBonded(pool).Amount
issuedDelegatorShares = equivalentBondedShares.Quo(exRate) // bshr/(bshr/delshr) = delshr
// bondedShare/(bondedShare/delegatedShare) = delegatedShare
issuedDelegatorShares := equivalentBondedShares.Quo(exRate)
v.DelegatorShares = v.DelegatorShares.Add(issuedDelegatorShares)
return v, pool, issuedDelegatorShares
}
// remove delegator shares from a validator
// NOTE this function assumes the shares have already been updated for the validator status
func (v Validator) RemoveDelShares(pool Pool,
delShares sdk.Rat) (validator2 Validator, p2 Pool, createdCoins int64) {
// RemoveDelShares removes delegator shares from a validator.
//
// NOTE: This function assumes the shares have already been updated for the
// validator status.
func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Rat) (Validator, Pool, int64) {
amount := v.DelegatorShareExRate(pool).Mul(delShares)
eqBondedSharesToRemove := NewBondedShares(amount)
v.DelegatorShares = v.DelegatorShares.Sub(delShares)
var createdCoins int64
switch v.Status() {
case sdk.Unbonded:
unbondedShares := eqBondedSharesToRemove.ToUnbonded(pool).Amount
@@ -265,15 +360,17 @@ func (v Validator) RemoveDelShares(pool Pool,
pool, createdCoins = pool.removeSharesBonded(eqBondedSharesToRemove.Amount)
v.PoolShares.Amount = v.PoolShares.Amount.Sub(eqBondedSharesToRemove.Amount)
}
return v, pool, createdCoins
}
// get the exchange rate of tokens over delegator shares
// DelegatorShareExRate gets the exchange rate of tokens over delegator shares.
// UNITS: eq-val-bonded-shares/delegator-shares
func (v Validator) DelegatorShareExRate(pool Pool) sdk.Rat {
if v.DelegatorShares.IsZero() {
return sdk.OneRat()
}
eqBondedShares := v.PoolShares.ToBonded(pool).Amount
return eqBondedShares.Quo(v.DelegatorShares)
}
@@ -293,16 +390,20 @@ func (v Validator) GetPower() sdk.Rat { return v.PoolShares.Bonded() }
func (v Validator) GetDelegatorShares() sdk.Rat { return v.DelegatorShares }
func (v Validator) GetBondHeight() int64 { return v.BondHeight }
//Human Friendly pretty printer
// HumanReadableString returns a human readable string representation of a
// validator. An error is returned if the owner or the owner's public key
// cannot be converted to Bech32 format.
func (v Validator) HumanReadableString() (string, error) {
bechOwner, err := sdk.Bech32ifyAcc(v.Owner)
if err != nil {
return "", err
}
bechVal, err := sdk.Bech32ifyValPub(v.PubKey)
if err != nil {
return "", err
}
resp := "Validator \n"
resp += fmt.Sprintf("Owner: %s\n", bechOwner)
resp += fmt.Sprintf("Validator: %s\n", bechVal)
+89 -2
View File
@@ -5,12 +5,89 @@ import (
"math/rand"
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
sdk "github.com/cosmos/cosmos-sdk/types"
tmtypes "github.com/tendermint/tendermint/types"
)
func TestValidatorEqual(t *testing.T) {
val1 := NewValidator(addr1, pk1, Description{})
val2 := NewValidator(addr1, pk1, Description{})
ok := val1.Equal(val2)
require.True(t, ok)
val2 = NewValidator(addr2, pk2, Description{})
ok = val1.Equal(val2)
require.False(t, ok)
}
func TestUpdateDescription(t *testing.T) {
d1 := Description{
Moniker: doNotModifyDescVal,
Identity: doNotModifyDescVal,
Website: doNotModifyDescVal,
Details: doNotModifyDescVal,
}
d2 := Description{
Website: "https://validator.cosmos",
Details: "Test validator",
}
d, err := d1.UpdateDescription(d2)
require.Nil(t, err)
require.Equal(t, d, d1)
}
func TestABCIValidator(t *testing.T) {
val := NewValidator(addr1, pk1, Description{})
abciVal := val.ABCIValidator()
require.Equal(t, tmtypes.TM2PB.PubKey(val.PubKey), abciVal.PubKey)
require.Equal(t, val.PoolShares.Bonded().RoundInt64(), abciVal.Power)
}
func TestABCIValidatorZero(t *testing.T) {
val := NewValidator(addr1, pk1, Description{})
abciVal := val.ABCIValidatorZero()
require.Equal(t, tmtypes.TM2PB.PubKey(val.PubKey), abciVal.PubKey)
require.Equal(t, int64(0), abciVal.Power)
}
func TestRemovePoolShares(t *testing.T) {
pool := InitialPool()
pool.LooseTokens = 10
val := Validator{
Owner: addr1,
PubKey: pk1,
PoolShares: NewBondedShares(sdk.NewRat(100)),
DelegatorShares: sdk.NewRat(100),
}
pool.BondedTokens = val.PoolShares.Bonded().RoundInt64()
pool.BondedShares = val.PoolShares.Bonded()
val, pool = val.UpdateStatus(pool, sdk.Bonded)
val, pool, tk := val.RemovePoolShares(pool, sdk.NewRat(10))
require.Equal(t, int64(90), val.PoolShares.Amount.RoundInt64())
require.Equal(t, int64(90), pool.BondedTokens)
require.Equal(t, int64(90), pool.BondedShares.RoundInt64())
require.Equal(t, int64(20), pool.LooseTokens)
require.Equal(t, int64(10), tk)
val, pool = val.UpdateStatus(pool, sdk.Unbonded)
val, pool, tk = val.RemovePoolShares(pool, sdk.NewRat(10))
require.Equal(t, int64(80), val.PoolShares.Amount.RoundInt64())
require.Equal(t, int64(0), pool.BondedTokens)
require.Equal(t, int64(0), pool.BondedShares.RoundInt64())
require.Equal(t, int64(30), pool.LooseTokens)
require.Equal(t, int64(10), tk)
}
func TestAddTokensValidatorBonded(t *testing.T) {
pool := InitialPool()
pool.LooseTokens = 10
@@ -230,3 +307,13 @@ func TestMultiValidatorIntegrationInvariants(t *testing.T) {
}
}
}
func TestHumanReadableString(t *testing.T) {
val := NewValidator(addr1, pk1, Description{})
// NOTE: Being that the validator's keypair is random, we cannot test the
// actual contents of the string.
valStr, err := val.HumanReadableString()
require.Nil(t, err)
require.NotEmpty(t, valStr)
}