Merge remote-tracking branch 'origin/develop' into rigel/a-validator-on-a-cliff
This commit is contained in:
+58
-60
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________________
|
||||
|
||||
@@ -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
@@ -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()...)
|
||||
}
|
||||
|
||||
@@ -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
@@ -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())
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user