Merge PR #2405: Unbonding and Redelegations Queue
This commit is contained in:
parent
d661ccb30e
commit
cd21427a7b
|
@ -41,6 +41,7 @@ BREAKING CHANGES
|
|||
* [x/gov] [#2195] Governance uses BFT Time
|
||||
* [x/gov] \#2256 Removed slashing for governance non-voting validators
|
||||
* [simulation] \#2162 Added back correct supply invariants
|
||||
* [x/stake] \#2393 Removed `CompleteUnbonding` and `CompleteRedelegation` Msg types, and instead added unbonding/redelegation queues to endblocker
|
||||
|
||||
* SDK
|
||||
* [core] \#2219 Update to Tendermint 0.24.0
|
||||
|
|
|
@ -97,9 +97,7 @@ func testAndRunTxs(app *GaiaApp) []simulation.WeightedOperation {
|
|||
{5, stakesim.SimulateMsgEditValidator(app.stakeKeeper)},
|
||||
{100, stakesim.SimulateMsgDelegate(app.accountMapper, app.stakeKeeper)},
|
||||
{100, stakesim.SimulateMsgBeginUnbonding(app.accountMapper, app.stakeKeeper)},
|
||||
{100, stakesim.SimulateMsgCompleteUnbonding(app.stakeKeeper)},
|
||||
{100, stakesim.SimulateMsgBeginRedelegate(app.accountMapper, app.stakeKeeper)},
|
||||
{100, stakesim.SimulateMsgCompleteRedelegate(app.stakeKeeper)},
|
||||
{100, slashingsim.SimulateMsgUnjail(app.slashingKeeper)},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,3 +16,34 @@ EndBlock() ValidatorSetChanges
|
|||
ClearTendermintUpdates()
|
||||
return vsc
|
||||
```
|
||||
|
||||
## CompleteUnbonding
|
||||
|
||||
Complete the unbonding and transfer the coins to the delegate. Realize any
|
||||
slashing that occurred during the unbonding period.
|
||||
|
||||
```golang
|
||||
unbondingQueue(currTime time.Time):
|
||||
// unbondings are in ordered queue from oldest to newest
|
||||
for all unbondings whose CompleteTime < currTime:
|
||||
validator = GetValidator(unbonding.ValidatorAddr)
|
||||
AddCoins(unbonding.DelegatorAddr, unbonding.Balance)
|
||||
removeUnbondingDelegation(unbonding)
|
||||
return
|
||||
```
|
||||
|
||||
## CompleteRedelegation
|
||||
|
||||
Note that unlike CompleteUnbonding slashing of redelegating shares does not
|
||||
take place during completion. Slashing on redelegated shares takes place
|
||||
actively as a slashing occurs. The redelegation completion queue serves simply to
|
||||
clean up state, as redelegations older than an unbonding period need not be kept,
|
||||
as that is the max time that their old validator's evidence can be used to slash them.
|
||||
|
||||
```golang
|
||||
redelegationQueue(currTime time.Time):
|
||||
// redelegations are in ordered queue from oldest to newest
|
||||
for all redelegations whose CompleteTime < currTime:
|
||||
removeRedelegation(redelegation)
|
||||
return
|
||||
```
|
|
@ -7,9 +7,7 @@ corresponding updates to the state. Transactions:
|
|||
* TxEditValidator
|
||||
* TxDelegation
|
||||
* TxStartUnbonding
|
||||
* TxCompleteUnbonding
|
||||
* TxRedelegate
|
||||
* TxCompleteRedelegation
|
||||
|
||||
Other important state changes:
|
||||
|
||||
|
@ -188,27 +186,6 @@ startUnbonding(tx TxStartUnbonding):
|
|||
return
|
||||
```
|
||||
|
||||
### TxCompleteUnbonding
|
||||
|
||||
Complete the unbonding and transfer the coins to the delegate. Perform any
|
||||
slashing that occurred during the unbonding period.
|
||||
|
||||
```golang
|
||||
type TxUnbondingComplete struct {
|
||||
DelegatorAddr sdk.Address
|
||||
ValidatorAddr sdk.Address
|
||||
}
|
||||
|
||||
redelegationComplete(tx TxRedelegate):
|
||||
unbonding = getUnbondingDelegation(tx.DelegatorAddr, tx.Validator)
|
||||
if unbonding.CompleteTime >= CurrentBlockTime && unbonding.CompleteHeight >= CurrentBlockHeight
|
||||
validator = GetValidator(tx.ValidatorAddr)
|
||||
returnTokens = ExpectedTokens * tx.startSlashRatio/validator.SlashRatio
|
||||
AddCoins(unbonding.DelegatorAddr, returnTokens)
|
||||
removeUnbondingDelegation(unbonding)
|
||||
return
|
||||
```
|
||||
|
||||
### TxRedelegation
|
||||
|
||||
The redelegation command allows delegators to instantly switch validators. Once
|
||||
|
@ -243,26 +220,6 @@ redelegate(tx TxRedelegate):
|
|||
return
|
||||
```
|
||||
|
||||
### TxCompleteRedelegation
|
||||
|
||||
Note that unlike TxCompleteUnbonding slashing of redelegating shares does not
|
||||
take place during completion. Slashing on redelegated shares takes place
|
||||
actively as a slashing occurs.
|
||||
|
||||
```golang
|
||||
type TxRedelegationComplete struct {
|
||||
DelegatorAddr Address
|
||||
ValidatorFrom Validator
|
||||
ValidatorTo Validator
|
||||
}
|
||||
|
||||
redelegationComplete(tx TxRedelegate):
|
||||
redelegation = getRedelegation(tx.DelegatorAddr, tx.validatorFrom, tx.validatorTo)
|
||||
if redelegation.CompleteTime >= CurrentBlockTime && redelegation.CompleteHeight >= CurrentBlockHeight
|
||||
removeRedelegation(redelegation)
|
||||
return
|
||||
```
|
||||
|
||||
### Update Validators
|
||||
|
||||
Within many transactions the validator set must be updated based on changes in
|
||||
|
|
|
@ -4,6 +4,7 @@ package types
|
|||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
|
||||
|
@ -181,6 +182,12 @@ func (c Context) WithBlockHeader(header abci.Header) Context {
|
|||
return c.withValue(contextKeyBlockHeader, header)
|
||||
}
|
||||
|
||||
func (c Context) WithBlockTime(newTime time.Time) Context {
|
||||
newHeader := c.BlockHeader()
|
||||
newHeader.Time = newTime
|
||||
return c.WithBlockHeader(newHeader)
|
||||
}
|
||||
|
||||
func (c Context) WithBlockHeight(height int64) Context {
|
||||
return c.withValue(contextKeyBlockHeight, height)
|
||||
}
|
||||
|
|
|
@ -306,6 +306,13 @@ func PrefixEndBytes(prefix []byte) []byte {
|
|||
return end
|
||||
}
|
||||
|
||||
// InclusiveEndBytes returns the []byte that would end a
|
||||
// range query such that the input would be included
|
||||
func InclusiveEndBytes(inclusiveBytes []byte) (exclusiveBytes []byte) {
|
||||
exclusiveBytes = append(inclusiveBytes, byte(0x00))
|
||||
return exclusiveBytes
|
||||
}
|
||||
|
||||
// TransientStoreKey is used for indexing transient stores in a MultiStore
|
||||
type TransientStoreKey struct {
|
||||
name string
|
||||
|
|
|
@ -70,9 +70,8 @@ func TestJailedValidatorDelegations(t *testing.T) {
|
|||
got = stake.NewHandler(stakeKeeper)(ctx, msgBeginUnbonding)
|
||||
require.True(t, got.IsOK(), "expected begin unbonding validator msg to be ok, got: %v", got)
|
||||
|
||||
msgCompleteUnbonding := stake.NewMsgCompleteUnbonding(sdk.AccAddress(valAddr), valAddr)
|
||||
got = stake.NewHandler(stakeKeeper)(ctx, msgCompleteUnbonding)
|
||||
require.True(t, got.IsOK(), "expected complete unbonding validator msg to be ok, got: %v", got)
|
||||
err := stakeKeeper.CompleteUnbonding(ctx, sdk.AccAddress(valAddr), valAddr)
|
||||
require.Nil(t, err, "expected complete unbonding validator to be ok, got: %v", err)
|
||||
|
||||
// verify validator still exists and is jailed
|
||||
validator, found := stakeKeeper.GetValidator(ctx, valAddr)
|
||||
|
|
|
@ -209,7 +209,6 @@ func GetCmdRedelegate(storeName string, cdc *codec.Codec) *cobra.Command {
|
|||
cmd.AddCommand(
|
||||
client.PostCommands(
|
||||
GetCmdBeginRedelegate(storeName, cdc),
|
||||
GetCmdCompleteRedelegate(cdc),
|
||||
)...)
|
||||
|
||||
return cmd
|
||||
|
@ -270,47 +269,6 @@ func GetCmdBeginRedelegate(storeName string, cdc *codec.Codec) *cobra.Command {
|
|||
return cmd
|
||||
}
|
||||
|
||||
// GetCmdCompleteRedelegate implements the complete redelegation command.
|
||||
func GetCmdCompleteRedelegate(cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "complete",
|
||||
Short: "complete redelegation",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
||||
cliCtx := context.NewCLIContext().
|
||||
WithCodec(cdc).
|
||||
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
|
||||
|
||||
delAddr, err := cliCtx.GetFromAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
valSrcAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidatorSrc))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
valDstAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidatorDst))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := stake.NewMsgCompleteRedelegate(delAddr, valSrcAddr, valDstAddr)
|
||||
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
}
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().AddFlagSet(fsRedelegation)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetCmdUnbond implements the unbond validator command.
|
||||
func GetCmdUnbond(storeName string, cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
|
@ -321,7 +279,6 @@ func GetCmdUnbond(storeName string, cdc *codec.Codec) *cobra.Command {
|
|||
cmd.AddCommand(
|
||||
client.PostCommands(
|
||||
GetCmdBeginUnbonding(storeName, cdc),
|
||||
GetCmdCompleteUnbonding(cdc),
|
||||
)...)
|
||||
|
||||
return cmd
|
||||
|
@ -374,39 +331,3 @@ func GetCmdBeginUnbonding(storeName string, cdc *codec.Codec) *cobra.Command {
|
|||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetCmdCompleteUnbonding implements the complete unbonding validator command.
|
||||
func GetCmdCompleteUnbonding(cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "complete",
|
||||
Short: "complete unbonding",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
||||
cliCtx := context.NewCLIContext().
|
||||
WithCodec(cdc).
|
||||
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
|
||||
|
||||
delAddr, err := cliCtx.GetFromAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
valAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidator))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := stake.NewMsgCompleteUnbonding(delAddr, valAddr)
|
||||
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
}
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().AddFlagSet(fsValidator)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
|
|
@ -41,31 +41,18 @@ type (
|
|||
SharesAmount string `json:"shares"`
|
||||
}
|
||||
|
||||
msgCompleteRedelegateInput struct {
|
||||
DelegatorAddr string `json:"delegator_addr"` // in bech32
|
||||
ValidatorSrcAddr string `json:"validator_src_addr"` // in bech32
|
||||
ValidatorDstAddr string `json:"validator_dst_addr"` // in bech32
|
||||
}
|
||||
|
||||
msgBeginUnbondingInput struct {
|
||||
DelegatorAddr string `json:"delegator_addr"` // in bech32
|
||||
ValidatorAddr string `json:"validator_addr"` // in bech32
|
||||
SharesAmount string `json:"shares"`
|
||||
}
|
||||
|
||||
msgCompleteUnbondingInput struct {
|
||||
DelegatorAddr string `json:"delegator_addr"` // in bech32
|
||||
ValidatorAddr string `json:"validator_addr"` // in bech32
|
||||
}
|
||||
|
||||
// the request body for edit delegations
|
||||
EditDelegationsReq struct {
|
||||
BaseReq utils.BaseReq `json:"base_req"`
|
||||
Delegations []msgDelegationsInput `json:"delegations"`
|
||||
BeginUnbondings []msgBeginUnbondingInput `json:"begin_unbondings"`
|
||||
CompleteUnbondings []msgCompleteUnbondingInput `json:"complete_unbondings"`
|
||||
BeginRedelegates []msgBeginRedelegateInput `json:"begin_redelegates"`
|
||||
CompleteRedelegates []msgCompleteRedelegateInput `json:"complete_redelegates"`
|
||||
BaseReq utils.BaseReq `json:"base_req"`
|
||||
Delegations []msgDelegationsInput `json:"delegations"`
|
||||
BeginUnbondings []msgBeginUnbondingInput `json:"begin_unbondings"`
|
||||
BeginRedelegates []msgBeginRedelegateInput `json:"begin_redelegates"`
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -106,9 +93,7 @@ func delegationsRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx conte
|
|||
// build messages
|
||||
messages := make([]sdk.Msg, len(req.Delegations)+
|
||||
len(req.BeginRedelegates)+
|
||||
len(req.CompleteRedelegates)+
|
||||
len(req.BeginUnbondings)+
|
||||
len(req.CompleteUnbondings))
|
||||
len(req.BeginUnbondings))
|
||||
|
||||
i := 0
|
||||
for _, msg := range req.Delegations {
|
||||
|
@ -177,39 +162,6 @@ func delegationsRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx conte
|
|||
i++
|
||||
}
|
||||
|
||||
for _, msg := range req.CompleteRedelegates {
|
||||
delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
valSrcAddr, err := sdk.ValAddressFromBech32(msg.ValidatorSrcAddr)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
valDstAddr, err := sdk.ValAddressFromBech32(msg.ValidatorDstAddr)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(info.GetPubKey().Address(), delAddr) {
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address")
|
||||
return
|
||||
}
|
||||
|
||||
messages[i] = stake.MsgCompleteRedelegate{
|
||||
DelegatorAddr: delAddr,
|
||||
ValidatorSrcAddr: valSrcAddr,
|
||||
ValidatorDstAddr: valDstAddr,
|
||||
}
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
for _, msg := range req.BeginUnbondings {
|
||||
delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr)
|
||||
if err != nil {
|
||||
|
@ -243,32 +195,6 @@ func delegationsRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx conte
|
|||
i++
|
||||
}
|
||||
|
||||
for _, msg := range req.CompleteUnbondings {
|
||||
delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
valAddr, err := sdk.ValAddressFromBech32(msg.ValidatorAddr)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(info.GetPubKey().Address(), delAddr) {
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address")
|
||||
return
|
||||
}
|
||||
|
||||
messages[i] = stake.MsgCompleteUnbonding{
|
||||
DelegatorAddr: delAddr,
|
||||
ValidatorAddr: valAddr,
|
||||
}
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
simulateGas, gas, err := client.ReadGasFlag(baseReq.Gas)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
|
|
|
@ -23,12 +23,8 @@ func NewHandler(k keeper.Keeper) sdk.Handler {
|
|||
return handleMsgDelegate(ctx, msg, k)
|
||||
case types.MsgBeginRedelegate:
|
||||
return handleMsgBeginRedelegate(ctx, msg, k)
|
||||
case types.MsgCompleteRedelegate:
|
||||
return handleMsgCompleteRedelegate(ctx, msg, k)
|
||||
case types.MsgBeginUnbonding:
|
||||
return handleMsgBeginUnbonding(ctx, msg, k)
|
||||
case types.MsgCompleteUnbonding:
|
||||
return handleMsgCompleteUnbonding(ctx, msg, k)
|
||||
default:
|
||||
return sdk.ErrTxDecode("invalid message parse in staking module").Result()
|
||||
}
|
||||
|
@ -37,6 +33,35 @@ func NewHandler(k keeper.Keeper) sdk.Handler {
|
|||
|
||||
// Called every block, process inflation, update validator set
|
||||
func EndBlocker(ctx sdk.Context, k keeper.Keeper) (ValidatorUpdates []abci.ValidatorUpdate) {
|
||||
endBlockerTags := sdk.EmptyTags()
|
||||
|
||||
matureUnbonds := k.DequeueAllMatureUnbondingQueue(ctx, ctx.BlockHeader().Time)
|
||||
for _, dvPair := range matureUnbonds {
|
||||
err := k.CompleteUnbonding(ctx, dvPair.DelegatorAddr, dvPair.ValidatorAddr)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
endBlockerTags.AppendTags(sdk.NewTags(
|
||||
tags.Action, ActionCompleteUnbonding,
|
||||
tags.Delegator, []byte(dvPair.DelegatorAddr.String()),
|
||||
tags.SrcValidator, []byte(dvPair.ValidatorAddr.String()),
|
||||
))
|
||||
}
|
||||
|
||||
matureRedelegations := k.DequeueAllMatureRedelegationQueue(ctx, ctx.BlockHeader().Time)
|
||||
for _, dvvTriplet := range matureRedelegations {
|
||||
err := k.CompleteRedelegation(ctx, dvvTriplet.DelegatorAddr, dvvTriplet.ValidatorSrcAddr, dvvTriplet.ValidatorDstAddr)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
endBlockerTags.AppendTags(sdk.NewTags(
|
||||
tags.Action, tags.ActionCompleteRedelegation,
|
||||
tags.Delegator, []byte(dvvTriplet.DelegatorAddr.String()),
|
||||
tags.SrcValidator, []byte(dvvTriplet.ValidatorSrcAddr.String()),
|
||||
tags.DstValidator, []byte(dvvTriplet.ValidatorDstAddr.String()),
|
||||
))
|
||||
}
|
||||
|
||||
pool := k.GetPool(ctx)
|
||||
|
||||
// Process provision inflation
|
||||
|
@ -185,62 +210,37 @@ func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper)
|
|||
}
|
||||
|
||||
func handleMsgBeginUnbonding(ctx sdk.Context, msg types.MsgBeginUnbonding, k keeper.Keeper) sdk.Result {
|
||||
err := k.BeginUnbonding(ctx, msg.DelegatorAddr, msg.ValidatorAddr, msg.SharesAmount)
|
||||
ubd, err := k.BeginUnbonding(ctx, msg.DelegatorAddr, msg.ValidatorAddr, msg.SharesAmount)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
||||
finishTime := types.MsgCdc.MustMarshalBinary(ubd.MinTime)
|
||||
|
||||
tags := sdk.NewTags(
|
||||
tags.Action, tags.ActionBeginUnbonding,
|
||||
tags.Delegator, []byte(msg.DelegatorAddr.String()),
|
||||
tags.SrcValidator, []byte(msg.ValidatorAddr.String()),
|
||||
tags.EndTime, finishTime,
|
||||
)
|
||||
return sdk.Result{Tags: tags}
|
||||
}
|
||||
|
||||
func handleMsgCompleteUnbonding(ctx sdk.Context, msg types.MsgCompleteUnbonding, k keeper.Keeper) sdk.Result {
|
||||
|
||||
err := k.CompleteUnbonding(ctx, msg.DelegatorAddr, msg.ValidatorAddr)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
||||
tags := sdk.NewTags(
|
||||
tags.Action, ActionCompleteUnbonding,
|
||||
tags.Delegator, []byte(msg.DelegatorAddr.String()),
|
||||
tags.SrcValidator, []byte(msg.ValidatorAddr.String()),
|
||||
)
|
||||
|
||||
return sdk.Result{Tags: tags}
|
||||
return sdk.Result{Data: finishTime, Tags: tags}
|
||||
}
|
||||
|
||||
func handleMsgBeginRedelegate(ctx sdk.Context, msg types.MsgBeginRedelegate, k keeper.Keeper) sdk.Result {
|
||||
err := k.BeginRedelegation(ctx, msg.DelegatorAddr, msg.ValidatorSrcAddr,
|
||||
red, err := k.BeginRedelegation(ctx, msg.DelegatorAddr, msg.ValidatorSrcAddr,
|
||||
msg.ValidatorDstAddr, msg.SharesAmount)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
||||
finishTime := types.MsgCdc.MustMarshalBinary(red.MinTime)
|
||||
|
||||
tags := sdk.NewTags(
|
||||
tags.Action, tags.ActionBeginRedelegation,
|
||||
tags.Delegator, []byte(msg.DelegatorAddr.String()),
|
||||
tags.SrcValidator, []byte(msg.ValidatorSrcAddr.String()),
|
||||
tags.DstValidator, []byte(msg.ValidatorDstAddr.String()),
|
||||
tags.EndTime, finishTime,
|
||||
)
|
||||
return sdk.Result{Tags: tags}
|
||||
}
|
||||
|
||||
func handleMsgCompleteRedelegate(ctx sdk.Context, msg types.MsgCompleteRedelegate, k keeper.Keeper) sdk.Result {
|
||||
err := k.CompleteRedelegation(ctx, msg.DelegatorAddr, msg.ValidatorSrcAddr, msg.ValidatorDstAddr)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
||||
tags := sdk.NewTags(
|
||||
tags.Action, tags.ActionCompleteRedelegation,
|
||||
tags.Delegator, []byte(msg.DelegatorAddr.String()),
|
||||
tags.SrcValidator, []byte(msg.ValidatorSrcAddr.String()),
|
||||
tags.DstValidator, []byte(msg.ValidatorDstAddr.String()),
|
||||
)
|
||||
return sdk.Result{Tags: tags}
|
||||
return sdk.Result{Data: finishTime, Tags: tags}
|
||||
}
|
||||
|
|
|
@ -125,11 +125,12 @@ func TestValidatorByPowerIndex(t *testing.T) {
|
|||
|
||||
// unbond self-delegation
|
||||
msgBeginUnbonding := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr), validatorAddr, sdk.NewDec(1000000))
|
||||
msgCompleteUnbonding := NewMsgCompleteUnbonding(sdk.AccAddress(validatorAddr), validatorAddr)
|
||||
got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
var finishTime time.Time
|
||||
types.MsgCdc.MustUnmarshalBinary(got.Data, &finishTime)
|
||||
ctx = ctx.WithBlockTime(finishTime)
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
|
@ -260,13 +261,14 @@ func TestLegacyValidatorDelegations(t *testing.T) {
|
|||
// unbond validator total self-delegations (which should jail the validator)
|
||||
unbondShares := sdk.NewDec(10)
|
||||
msgBeginUnbonding := NewMsgBeginUnbonding(sdk.AccAddress(valAddr), valAddr, unbondShares)
|
||||
msgCompleteUnbonding := NewMsgCompleteUnbonding(sdk.AccAddress(valAddr), valAddr)
|
||||
|
||||
got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper)
|
||||
require.True(t, got.IsOK(), "expected begin unbonding validator msg to be ok, got %v", got)
|
||||
|
||||
got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper)
|
||||
require.True(t, got.IsOK(), "expected complete unbonding validator msg to be ok, got %v", got)
|
||||
var finishTime time.Time
|
||||
types.MsgCdc.MustUnmarshalBinary(got.Data, &finishTime)
|
||||
ctx = ctx.WithBlockTime(finishTime)
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
// verify the validator record still exists, is jailed, and has correct tokens
|
||||
validator, found = keeper.GetValidator(ctx, valAddr)
|
||||
|
@ -427,13 +429,14 @@ func TestIncrementsMsgUnbond(t *testing.T) {
|
|||
// TODO use decimals here
|
||||
unbondShares := sdk.NewDec(10)
|
||||
msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares)
|
||||
msgCompleteUnbonding := NewMsgCompleteUnbonding(delegatorAddr, validatorAddr)
|
||||
numUnbonds := 5
|
||||
for i := 0; i < numUnbonds; i++ {
|
||||
got := handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper)
|
||||
require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got)
|
||||
got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper)
|
||||
require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got)
|
||||
var finishTime time.Time
|
||||
types.MsgCdc.MustUnmarshalBinary(got.Data, &finishTime)
|
||||
ctx = ctx.WithBlockTime(finishTime)
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
//Check that the accounts and the bond account have the appropriate values
|
||||
validator, found = keeper.GetValidator(ctx, validatorAddr)
|
||||
|
@ -522,11 +525,12 @@ func TestMultipleMsgCreateValidator(t *testing.T) {
|
|||
_, found := keeper.GetValidator(ctx, validatorAddr)
|
||||
require.True(t, found)
|
||||
msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddrs[i], validatorAddr, sdk.NewDec(10)) // remove delegation
|
||||
msgCompleteUnbonding := NewMsgCompleteUnbonding(delegatorAddrs[i], validatorAddr)
|
||||
got := handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper)
|
||||
require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got)
|
||||
got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper)
|
||||
require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got)
|
||||
var finishTime time.Time
|
||||
types.MsgCdc.MustUnmarshalBinary(got.Data, &finishTime)
|
||||
ctx = ctx.WithBlockTime(finishTime)
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
//Check that the account is unbonded
|
||||
validators := keeper.GetValidators(ctx, 100)
|
||||
|
@ -569,6 +573,10 @@ func TestMultipleMsgDelegate(t *testing.T) {
|
|||
msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewDec(10))
|
||||
got := handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper)
|
||||
require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got)
|
||||
var finishTime time.Time
|
||||
types.MsgCdc.MustUnmarshalBinary(got.Data, &finishTime)
|
||||
ctx = ctx.WithBlockTime(finishTime)
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
//Check that the account is unbonded
|
||||
_, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr)
|
||||
|
@ -591,12 +599,14 @@ func TestJailValidator(t *testing.T) {
|
|||
got = handleMsgDelegate(ctx, msgDelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected ok, got %v", got)
|
||||
|
||||
validator, _ := keeper.GetValidator(ctx, validatorAddr)
|
||||
|
||||
// unbond the validators bond portion
|
||||
msgBeginUnbondingValidator := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr), validatorAddr, sdk.NewDec(10))
|
||||
got = handleMsgBeginUnbonding(ctx, msgBeginUnbondingValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error: %v", got)
|
||||
var finishTime time.Time
|
||||
types.MsgCdc.MustUnmarshalBinary(got.Data, &finishTime)
|
||||
ctx = ctx.WithBlockTime(finishTime)
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, validatorAddr)
|
||||
require.True(t, found)
|
||||
|
@ -608,11 +618,11 @@ func TestJailValidator(t *testing.T) {
|
|||
|
||||
// test that the delegator can still withdraw their bonds
|
||||
msgBeginUnbondingDelegator := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewDec(10))
|
||||
msgCompleteUnbondingDelegator := NewMsgCompleteUnbonding(delegatorAddr, validatorAddr)
|
||||
got = handleMsgBeginUnbonding(ctx, msgBeginUnbondingDelegator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error")
|
||||
got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbondingDelegator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error")
|
||||
types.MsgCdc.MustUnmarshalBinary(got.Data, &finishTime)
|
||||
ctx = ctx.WithBlockTime(finishTime)
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
// verify that the pubkey can now be reused
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
|
@ -633,30 +643,74 @@ func TestUnbondingPeriod(t *testing.T) {
|
|||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
// begin unbonding
|
||||
msgBeginUnbonding := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr), validatorAddr, sdk.NewDec(10))
|
||||
got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error")
|
||||
origHeader := ctx.BlockHeader()
|
||||
|
||||
_, found := keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr)
|
||||
require.True(t, found, "should not have unbonded")
|
||||
|
||||
// cannot complete unbonding at same time
|
||||
msgCompleteUnbonding := NewMsgCompleteUnbonding(sdk.AccAddress(validatorAddr), validatorAddr)
|
||||
got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper)
|
||||
require.True(t, !got.IsOK(), "expected an error")
|
||||
EndBlocker(ctx, keeper)
|
||||
_, found = keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr)
|
||||
require.True(t, found, "should not have unbonded")
|
||||
|
||||
// cannot complete unbonding at time 6 seconds later
|
||||
origHeader := ctx.BlockHeader()
|
||||
headerTime6 := origHeader
|
||||
headerTime6.Time = headerTime6.Time.Add(time.Second * 6)
|
||||
ctx = ctx.WithBlockHeader(headerTime6)
|
||||
got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper)
|
||||
require.True(t, !got.IsOK(), "expected an error")
|
||||
ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6))
|
||||
EndBlocker(ctx, keeper)
|
||||
_, found = keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr)
|
||||
require.True(t, found, "should not have unbonded")
|
||||
|
||||
// can complete unbonding at time 7 seconds later
|
||||
headerTime7 := origHeader
|
||||
headerTime7.Time = headerTime7.Time.Add(time.Second * 7)
|
||||
ctx = ctx.WithBlockHeader(headerTime7)
|
||||
got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper)
|
||||
ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7))
|
||||
EndBlocker(ctx, keeper)
|
||||
_, found = keeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr)
|
||||
require.False(t, found, "should have unbonded")
|
||||
}
|
||||
|
||||
func TestUnbondingFromUnbondingValidator(t *testing.T) {
|
||||
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
|
||||
validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1]
|
||||
|
||||
// create the validator
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], 10)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
// bond a delegator
|
||||
msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, 10)
|
||||
got = handleMsgDelegate(ctx, msgDelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected ok, got %v", got)
|
||||
|
||||
// unbond the validators bond portion
|
||||
msgBeginUnbondingValidator := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr), validatorAddr, sdk.NewDec(10))
|
||||
got = handleMsgBeginUnbonding(ctx, msgBeginUnbondingValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error")
|
||||
|
||||
// change the ctx to Block Time one second before the validator would have unbonded
|
||||
var finishTime time.Time
|
||||
types.MsgCdc.MustUnmarshalBinary(got.Data, &finishTime)
|
||||
ctx = ctx.WithBlockTime(finishTime.Add(time.Second * -1))
|
||||
|
||||
// unbond the delegator from the validator
|
||||
msgBeginUnbondingDelegator := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewDec(10))
|
||||
got = handleMsgBeginUnbonding(ctx, msgBeginUnbondingDelegator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error")
|
||||
|
||||
// move the Block time forward by one second
|
||||
ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(time.Second * 1))
|
||||
|
||||
// Run the EndBlocker
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
// Check to make sure that the unbonding delegation is no longer in state
|
||||
// (meaning it was deleted in the above EndBlocker)
|
||||
_, found := keeper.GetUnbondingDelegation(ctx, delegatorAddr, validatorAddr)
|
||||
require.False(t, found, "should be removed from state")
|
||||
}
|
||||
|
||||
func TestRedelegationPeriod(t *testing.T) {
|
||||
|
@ -697,25 +751,24 @@ func TestRedelegationPeriod(t *testing.T) {
|
|||
bal2 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins()
|
||||
require.Equal(t, bal1, bal2)
|
||||
|
||||
origHeader := ctx.BlockHeader()
|
||||
|
||||
// cannot complete redelegation at same time
|
||||
msgCompleteRedelegate := NewMsgCompleteRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2)
|
||||
got = handleMsgCompleteRedelegate(ctx, msgCompleteRedelegate, keeper)
|
||||
require.True(t, !got.IsOK(), "expected an error")
|
||||
EndBlocker(ctx, keeper)
|
||||
_, found := keeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2)
|
||||
require.True(t, found, "should not have unbonded")
|
||||
|
||||
// cannot complete redelegation at time 6 seconds later
|
||||
origHeader := ctx.BlockHeader()
|
||||
headerTime6 := origHeader
|
||||
headerTime6.Time = headerTime6.Time.Add(time.Second * 6)
|
||||
ctx = ctx.WithBlockHeader(headerTime6)
|
||||
got = handleMsgCompleteRedelegate(ctx, msgCompleteRedelegate, keeper)
|
||||
require.True(t, !got.IsOK(), "expected an error")
|
||||
ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 6))
|
||||
EndBlocker(ctx, keeper)
|
||||
_, found = keeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2)
|
||||
require.True(t, found, "should not have unbonded")
|
||||
|
||||
// can complete redelegation at time 7 seconds later
|
||||
headerTime7 := origHeader
|
||||
headerTime7.Time = headerTime7.Time.Add(time.Second * 7)
|
||||
ctx = ctx.WithBlockHeader(headerTime7)
|
||||
got = handleMsgCompleteRedelegate(ctx, msgCompleteRedelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error")
|
||||
ctx = ctx.WithBlockTime(origHeader.Time.Add(time.Second * 7))
|
||||
EndBlocker(ctx, keeper)
|
||||
_, found = keeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2)
|
||||
require.False(t, found, "should have unbonded")
|
||||
}
|
||||
|
||||
func TestTransitiveRedelegation(t *testing.T) {
|
||||
|
@ -753,9 +806,7 @@ func TestTransitiveRedelegation(t *testing.T) {
|
|||
require.True(t, !got.IsOK(), "expected an error, msg: %v", msgBeginRedelegate)
|
||||
|
||||
// complete first redelegation
|
||||
msgCompleteRedelegate := NewMsgCompleteRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2)
|
||||
got = handleMsgCompleteRedelegate(ctx, msgCompleteRedelegate, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error")
|
||||
EndBlocker(ctx, keeper)
|
||||
|
||||
// now should be able to redelegate from the second validator to the third
|
||||
got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper)
|
||||
|
|
|
@ -155,6 +155,57 @@ func (k Keeper) RemoveUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDe
|
|||
store.Delete(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr))
|
||||
}
|
||||
|
||||
// gets a specific unbonding queue timeslice. A timeslice is a slice of DVPairs corresponding to unbonding delegations
|
||||
// that expire at a certain time.
|
||||
func (k Keeper) GetUnbondingQueueTimeSlice(ctx sdk.Context, timestamp time.Time) (dvPairs []types.DVPair) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
bz := store.Get(GetUnbondingDelegationTimeKey(timestamp))
|
||||
if bz == nil {
|
||||
return []types.DVPair{}
|
||||
}
|
||||
k.cdc.MustUnmarshalBinary(bz, &dvPairs)
|
||||
return dvPairs
|
||||
}
|
||||
|
||||
// Sets a specific unbonding queue timeslice.
|
||||
func (k Keeper) SetUnbondingQueueTimeSlice(ctx sdk.Context, timestamp time.Time, keys []types.DVPair) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
bz := k.cdc.MustMarshalBinary(keys)
|
||||
store.Set(GetUnbondingDelegationTimeKey(timestamp), bz)
|
||||
}
|
||||
|
||||
// Insert an unbonding delegation to the appropriate timeslice in the unbonding queue
|
||||
func (k Keeper) InsertUnbondingQueue(ctx sdk.Context, ubd types.UnbondingDelegation) {
|
||||
timeSlice := k.GetUnbondingQueueTimeSlice(ctx, ubd.MinTime)
|
||||
dvPair := types.DVPair{ubd.DelegatorAddr, ubd.ValidatorAddr}
|
||||
if len(timeSlice) == 0 {
|
||||
k.SetUnbondingQueueTimeSlice(ctx, ubd.MinTime, []types.DVPair{dvPair})
|
||||
} else {
|
||||
timeSlice = append(timeSlice, dvPair)
|
||||
k.SetUnbondingQueueTimeSlice(ctx, ubd.MinTime, timeSlice)
|
||||
}
|
||||
}
|
||||
|
||||
// Returns all the unbonding queue timeslices from time 0 until endTime
|
||||
func (k Keeper) UnbondingQueueIterator(ctx sdk.Context, endTime time.Time) sdk.Iterator {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
return store.Iterator(UnbondingQueueKey, sdk.InclusiveEndBytes(GetUnbondingDelegationTimeKey(endTime)))
|
||||
}
|
||||
|
||||
// Returns a concatenated list of all the timeslices before currTime, and deletes the timeslices from the queue
|
||||
func (k Keeper) DequeueAllMatureUnbondingQueue(ctx sdk.Context, currTime time.Time) (matureUnbonds []types.DVPair) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
// gets an iterator for all timeslices from time 0 until the current Blockheader time
|
||||
unbondingTimesliceIterator := k.UnbondingQueueIterator(ctx, ctx.BlockHeader().Time)
|
||||
for ; unbondingTimesliceIterator.Valid(); unbondingTimesliceIterator.Next() {
|
||||
timeslice := []types.DVPair{}
|
||||
k.cdc.MustUnmarshalBinary(unbondingTimesliceIterator.Value(), ×lice)
|
||||
matureUnbonds = append(matureUnbonds, timeslice...)
|
||||
store.Delete(unbondingTimesliceIterator.Key())
|
||||
}
|
||||
return matureUnbonds
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________________
|
||||
|
||||
// return a given amount of all the delegator redelegations
|
||||
|
@ -241,6 +292,57 @@ func (k Keeper) RemoveRedelegation(ctx sdk.Context, red types.Redelegation) {
|
|||
store.Delete(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr))
|
||||
}
|
||||
|
||||
// Gets a specific redelegation queue timeslice. A timeslice is a slice of DVVTriplets corresponding to redelegations
|
||||
// that expire at a certain time.
|
||||
func (k Keeper) GetRedelegationQueueTimeSlice(ctx sdk.Context, timestamp time.Time) (dvvTriplets []types.DVVTriplet) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
bz := store.Get(GetRedelegationTimeKey(timestamp))
|
||||
if bz == nil {
|
||||
return []types.DVVTriplet{}
|
||||
}
|
||||
k.cdc.MustUnmarshalBinary(bz, &dvvTriplets)
|
||||
return dvvTriplets
|
||||
}
|
||||
|
||||
// Sets a specific redelegation queue timeslice.
|
||||
func (k Keeper) SetRedelegationQueueTimeSlice(ctx sdk.Context, timestamp time.Time, keys []types.DVVTriplet) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
bz := k.cdc.MustMarshalBinary(keys)
|
||||
store.Set(GetRedelegationTimeKey(timestamp), bz)
|
||||
}
|
||||
|
||||
// Insert an redelegation delegation to the appropriate timeslice in the redelegation queue
|
||||
func (k Keeper) InsertRedelegationQueue(ctx sdk.Context, red types.Redelegation) {
|
||||
timeSlice := k.GetRedelegationQueueTimeSlice(ctx, red.MinTime)
|
||||
dvvTriplet := types.DVVTriplet{red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr}
|
||||
if len(timeSlice) == 0 {
|
||||
k.SetRedelegationQueueTimeSlice(ctx, red.MinTime, []types.DVVTriplet{dvvTriplet})
|
||||
} else {
|
||||
timeSlice = append(timeSlice, dvvTriplet)
|
||||
k.SetRedelegationQueueTimeSlice(ctx, red.MinTime, timeSlice)
|
||||
}
|
||||
}
|
||||
|
||||
// Returns all the redelegation queue timeslices from time 0 until endTime
|
||||
func (k Keeper) RedelegationQueueIterator(ctx sdk.Context, endTime time.Time) sdk.Iterator {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
return store.Iterator(RedelegationQueueKey, sdk.InclusiveEndBytes(GetRedelegationTimeKey(endTime)))
|
||||
}
|
||||
|
||||
// Returns a concatenated list of all the timeslices before currTime, and deletes the timeslices from the queue
|
||||
func (k Keeper) DequeueAllMatureRedelegationQueue(ctx sdk.Context, currTime time.Time) (matureRedelegations []types.DVVTriplet) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
// gets an iterator for all timeslices from time 0 until the current Blockheader time
|
||||
redelegationTimesliceIterator := k.RedelegationQueueIterator(ctx, ctx.BlockHeader().Time)
|
||||
for ; redelegationTimesliceIterator.Valid(); redelegationTimesliceIterator.Next() {
|
||||
timeslice := []types.DVVTriplet{}
|
||||
k.cdc.MustUnmarshalBinary(redelegationTimesliceIterator.Value(), ×lice)
|
||||
matureRedelegations = append(matureRedelegations, timeslice...)
|
||||
store.Delete(redelegationTimesliceIterator.Key())
|
||||
}
|
||||
return matureRedelegations
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________________
|
||||
|
||||
// Perform a delegation, set/update everything necessary within the store.
|
||||
|
@ -339,6 +441,7 @@ func (k Keeper) getBeginInfo(ctx sdk.Context, params types.Params, valSrcAddr sd
|
|||
minTime time.Time, height int64, completeNow bool) {
|
||||
|
||||
validator, found := k.GetValidator(ctx, valSrcAddr)
|
||||
|
||||
switch {
|
||||
case !found || validator.Status == sdk.Bonded:
|
||||
|
||||
|
@ -362,31 +465,32 @@ func (k Keeper) getBeginInfo(ctx sdk.Context, params types.Params, valSrcAddr sd
|
|||
|
||||
// begin unbonding an unbonding record
|
||||
func (k Keeper) BeginUnbonding(ctx sdk.Context,
|
||||
delAddr sdk.AccAddress, valAddr sdk.ValAddress, sharesAmount sdk.Dec) sdk.Error {
|
||||
delAddr sdk.AccAddress, valAddr sdk.ValAddress, sharesAmount sdk.Dec) (types.UnbondingDelegation, sdk.Error) {
|
||||
|
||||
// TODO quick fix, instead we should use an index, see https://github.com/cosmos/cosmos-sdk/issues/1402
|
||||
_, found := k.GetUnbondingDelegation(ctx, delAddr, valAddr)
|
||||
if found {
|
||||
return types.ErrExistingUnbondingDelegation(k.Codespace())
|
||||
}
|
||||
|
||||
returnAmount, err := k.unbond(ctx, delAddr, valAddr, sharesAmount)
|
||||
if err != nil {
|
||||
return err
|
||||
return types.UnbondingDelegation{}, types.ErrExistingUnbondingDelegation(k.Codespace())
|
||||
}
|
||||
|
||||
// create the unbonding delegation
|
||||
params := k.GetParams(ctx)
|
||||
minTime, height, completeNow := k.getBeginInfo(ctx, params, valAddr)
|
||||
|
||||
returnAmount, err := k.unbond(ctx, delAddr, valAddr, sharesAmount)
|
||||
if err != nil {
|
||||
return types.UnbondingDelegation{}, err
|
||||
}
|
||||
|
||||
balance := sdk.NewCoin(params.BondDenom, returnAmount.RoundInt())
|
||||
|
||||
// no need to create the ubd object just complete now
|
||||
if completeNow {
|
||||
_, _, err := k.bankKeeper.AddCoins(ctx, delAddr, sdk.Coins{balance})
|
||||
if err != nil {
|
||||
return err
|
||||
return types.UnbondingDelegation{}, err
|
||||
}
|
||||
return nil
|
||||
return types.UnbondingDelegation{MinTime: minTime}, nil
|
||||
}
|
||||
|
||||
ubd := types.UnbondingDelegation{
|
||||
|
@ -398,10 +502,12 @@ func (k Keeper) BeginUnbonding(ctx sdk.Context,
|
|||
InitialBalance: balance,
|
||||
}
|
||||
k.SetUnbondingDelegation(ctx, ubd)
|
||||
return nil
|
||||
k.InsertUnbondingQueue(ctx, ubd)
|
||||
return ubd, nil
|
||||
}
|
||||
|
||||
// complete unbonding an unbonding record
|
||||
// CONTRACT: Expects unbonding passed in has finished the unbonding period
|
||||
func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) sdk.Error {
|
||||
|
||||
ubd, found := k.GetUnbondingDelegation(ctx, delAddr, valAddr)
|
||||
|
@ -409,12 +515,6 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, valAd
|
|||
return types.ErrNoUnbondingDelegation(k.Codespace())
|
||||
}
|
||||
|
||||
// ensure that enough time has passed
|
||||
ctxTime := ctx.BlockHeader().Time
|
||||
if ubd.MinTime.After(ctxTime) {
|
||||
return types.ErrNotMature(k.Codespace(), "unbonding", "unit-time", ubd.MinTime, ctxTime)
|
||||
}
|
||||
|
||||
_, _, err := k.bankKeeper.AddCoins(ctx, ubd.DelegatorAddr, sdk.Coins{ubd.Balance})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -425,34 +525,34 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, valAd
|
|||
|
||||
// complete unbonding an unbonding record
|
||||
func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress,
|
||||
valSrcAddr, valDstAddr sdk.ValAddress, sharesAmount sdk.Dec) sdk.Error {
|
||||
valSrcAddr, valDstAddr sdk.ValAddress, sharesAmount sdk.Dec) (types.Redelegation, sdk.Error) {
|
||||
|
||||
// check if this is a transitive redelegation
|
||||
if k.HasReceivingRedelegation(ctx, delAddr, valSrcAddr) {
|
||||
return types.ErrTransitiveRedelegation(k.Codespace())
|
||||
return types.Redelegation{}, types.ErrTransitiveRedelegation(k.Codespace())
|
||||
}
|
||||
|
||||
returnAmount, err := k.unbond(ctx, delAddr, valSrcAddr, sharesAmount)
|
||||
if err != nil {
|
||||
return err
|
||||
return types.Redelegation{}, err
|
||||
}
|
||||
|
||||
params := k.GetParams(ctx)
|
||||
returnCoin := sdk.NewCoin(params.BondDenom, returnAmount.RoundInt())
|
||||
dstValidator, found := k.GetValidator(ctx, valDstAddr)
|
||||
if !found {
|
||||
return types.ErrBadRedelegationDst(k.Codespace())
|
||||
return types.Redelegation{}, types.ErrBadRedelegationDst(k.Codespace())
|
||||
}
|
||||
sharesCreated, err := k.Delegate(ctx, delAddr, returnCoin, dstValidator, false)
|
||||
if err != nil {
|
||||
return err
|
||||
return types.Redelegation{}, err
|
||||
}
|
||||
|
||||
// create the unbonding delegation
|
||||
minTime, height, completeNow := k.getBeginInfo(ctx, params, valSrcAddr)
|
||||
|
||||
if completeNow { // no need to create the redelegation object
|
||||
return nil
|
||||
return types.Redelegation{MinTime: minTime}, nil
|
||||
}
|
||||
|
||||
red := types.Redelegation{
|
||||
|
@ -467,7 +567,8 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress,
|
|||
InitialBalance: returnCoin,
|
||||
}
|
||||
k.SetRedelegation(ctx, red)
|
||||
return nil
|
||||
k.InsertRedelegationQueue(ctx, red)
|
||||
return red, nil
|
||||
}
|
||||
|
||||
// complete unbonding an ongoing redelegation
|
||||
|
|
|
@ -250,7 +250,7 @@ func TestUndelegateSelfDelegation(t *testing.T) {
|
|||
keeper.SetDelegation(ctx, delegation)
|
||||
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
|
||||
_, err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
|
||||
require.NoError(t, err)
|
||||
|
||||
// end block
|
||||
|
@ -306,7 +306,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) {
|
|||
|
||||
// unbond the all self-delegation to put validator in unbonding state
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
|
||||
_, err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
|
||||
require.NoError(t, err)
|
||||
|
||||
// end block
|
||||
|
@ -328,7 +328,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) {
|
|||
ctx = ctx.WithBlockHeader(header)
|
||||
|
||||
// unbond some of the other delegation's shares
|
||||
err = keeper.BeginUnbonding(ctx, addrDels[0], addrVals[0], sdk.NewDec(6))
|
||||
_, err = keeper.BeginUnbonding(ctx, addrDels[0], addrVals[0], sdk.NewDec(6))
|
||||
require.NoError(t, err)
|
||||
|
||||
// retrieve the unbonding delegation
|
||||
|
@ -382,7 +382,7 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) {
|
|||
ctx = ctx.WithBlockHeader(header)
|
||||
|
||||
// unbond the all self-delegation to put validator in unbonding state
|
||||
err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
|
||||
_, err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
|
||||
require.NoError(t, err)
|
||||
|
||||
// end block
|
||||
|
@ -404,7 +404,7 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) {
|
|||
ctx = ctx.WithBlockHeader(header)
|
||||
|
||||
// unbond some of the other delegation's shares
|
||||
err = keeper.BeginUnbonding(ctx, addrDels[0], addrVals[0], sdk.NewDec(6))
|
||||
_, err = keeper.BeginUnbonding(ctx, addrDels[0], addrVals[0], sdk.NewDec(6))
|
||||
require.NoError(t, err)
|
||||
|
||||
// no ubd should have been found, coins should have been returned direcly to account
|
||||
|
@ -553,7 +553,7 @@ func TestRedelegateSelfDelegation(t *testing.T) {
|
|||
}
|
||||
keeper.SetDelegation(ctx, delegation)
|
||||
|
||||
err := keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(10))
|
||||
_, err := keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(10))
|
||||
require.NoError(t, err)
|
||||
|
||||
// end block
|
||||
|
@ -618,7 +618,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) {
|
|||
ctx = ctx.WithBlockHeader(header)
|
||||
|
||||
// unbond the all self-delegation to put validator in unbonding state
|
||||
err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
|
||||
_, err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
|
||||
require.NoError(t, err)
|
||||
|
||||
// end block
|
||||
|
@ -640,7 +640,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) {
|
|||
ctx = ctx.WithBlockHeader(header)
|
||||
|
||||
// unbond some of the other delegation's shares
|
||||
err = keeper.BeginRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1], sdk.NewDec(6))
|
||||
_, err = keeper.BeginRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1], sdk.NewDec(6))
|
||||
require.NoError(t, err)
|
||||
|
||||
// retrieve the unbonding delegation
|
||||
|
@ -704,7 +704,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) {
|
|||
ctx = ctx.WithBlockHeader(header)
|
||||
|
||||
// unbond the all self-delegation to put validator in unbonding state
|
||||
err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
|
||||
_, err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10))
|
||||
require.NoError(t, err)
|
||||
|
||||
// end block
|
||||
|
@ -726,7 +726,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) {
|
|||
ctx = ctx.WithBlockHeader(header)
|
||||
|
||||
// unbond some of the other delegation's shares
|
||||
err = keeper.BeginRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1], sdk.NewDec(6))
|
||||
_, err = keeper.BeginRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1], sdk.NewDec(6))
|
||||
require.NoError(t, err)
|
||||
|
||||
// no ubd should have been found, coins should have been returned direcly to account
|
||||
|
|
|
@ -2,6 +2,7 @@ package keeper
|
|||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
|
@ -25,6 +26,8 @@ var (
|
|||
RedelegationKey = []byte{0x0A} // key for a redelegation
|
||||
RedelegationByValSrcIndexKey = []byte{0x0B} // prefix for each key for an redelegation, by source validator operator
|
||||
RedelegationByValDstIndexKey = []byte{0x0C} // prefix for each key for an redelegation, by destination validator operator
|
||||
UnbondingQueueKey = []byte{0x0D} // prefix for the timestamps in unbonding queue
|
||||
RedelegationQueueKey = []byte{0x0E} // prefix for the timestamps in redelegations queue
|
||||
)
|
||||
|
||||
const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch
|
||||
|
@ -134,6 +137,12 @@ func GetUBDsByValIndexKey(valAddr sdk.ValAddress) []byte {
|
|||
return append(UnbondingDelegationByValIndexKey, valAddr.Bytes()...)
|
||||
}
|
||||
|
||||
// gets the prefix for all unbonding delegations from a delegator
|
||||
func GetUnbondingDelegationTimeKey(timestamp time.Time) []byte {
|
||||
bz := types.MsgCdc.MustMarshalBinary(timestamp)
|
||||
return append(UnbondingQueueKey, bz...)
|
||||
}
|
||||
|
||||
//________________________________________________________________________________
|
||||
|
||||
// gets the key for a redelegation
|
||||
|
@ -202,6 +211,12 @@ func GetREDKeyFromValDstIndexKey(indexKey []byte) []byte {
|
|||
return GetREDKey(delAddr, valSrcAddr, valDstAddr)
|
||||
}
|
||||
|
||||
// gets the prefix for all unbonding delegations from a delegator
|
||||
func GetRedelegationTimeKey(timestamp time.Time) []byte {
|
||||
bz, _ := timestamp.MarshalBinary()
|
||||
return append(RedelegationQueueKey, bz...)
|
||||
}
|
||||
|
||||
//______________
|
||||
|
||||
// gets the prefix keyspace for redelegations from a delegator
|
||||
|
|
|
@ -62,9 +62,7 @@ func MakeTestCodec() *codec.Codec {
|
|||
cdc.RegisterConcrete(types.MsgCreateValidator{}, "test/stake/CreateValidator", nil)
|
||||
cdc.RegisterConcrete(types.MsgEditValidator{}, "test/stake/EditValidator", nil)
|
||||
cdc.RegisterConcrete(types.MsgBeginUnbonding{}, "test/stake/BeginUnbonding", nil)
|
||||
cdc.RegisterConcrete(types.MsgCompleteUnbonding{}, "test/stake/CompleteUnbonding", nil)
|
||||
cdc.RegisterConcrete(types.MsgBeginRedelegate{}, "test/stake/BeginRedelegate", nil)
|
||||
cdc.RegisterConcrete(types.MsgCompleteRedelegate{}, "test/stake/CompleteRedelegate", nil)
|
||||
|
||||
// Register AppAccount
|
||||
cdc.RegisterInterface((*auth.Account)(nil), nil)
|
||||
|
|
|
@ -178,33 +178,6 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.
|
|||
}
|
||||
}
|
||||
|
||||
// SimulateMsgCompleteUnbonding
|
||||
func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
|
||||
handler := stake.NewHandler(k)
|
||||
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
|
||||
|
||||
validatorAcc := simulation.RandomAcc(r, accs)
|
||||
validatorAddress := sdk.ValAddress(validatorAcc.Address)
|
||||
delegatorAcc := simulation.RandomAcc(r, accs)
|
||||
delegatorAddress := delegatorAcc.Address
|
||||
msg := stake.MsgCompleteUnbonding{
|
||||
DelegatorAddr: delegatorAddress,
|
||||
ValidatorAddr: validatorAddress,
|
||||
}
|
||||
if msg.ValidateBasic() != nil {
|
||||
return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
||||
}
|
||||
ctx, write := ctx.CacheContext()
|
||||
result := handler(ctx, msg)
|
||||
if result.IsOK() {
|
||||
write()
|
||||
}
|
||||
event(fmt.Sprintf("stake/MsgCompleteUnbonding/%v", result.IsOK()))
|
||||
action = fmt.Sprintf("TestMsgCompleteUnbonding: ok %v, msg %s", result.IsOK(), msg.GetSignBytes())
|
||||
return action, nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
// SimulateMsgBeginRedelegate
|
||||
func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
||||
handler := stake.NewHandler(k)
|
||||
|
@ -245,36 +218,6 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation
|
|||
}
|
||||
}
|
||||
|
||||
// SimulateMsgCompleteRedelegate
|
||||
func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation {
|
||||
handler := stake.NewHandler(k)
|
||||
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
|
||||
|
||||
validatorSrcAcc := simulation.RandomAcc(r, accs)
|
||||
validatorSrcAddress := sdk.ValAddress(validatorSrcAcc.Address)
|
||||
validatorDstAcc := simulation.RandomAcc(r, accs)
|
||||
validatorDstAddress := sdk.ValAddress(validatorDstAcc.Address)
|
||||
delegatorAcc := simulation.RandomAcc(r, accs)
|
||||
delegatorAddress := delegatorAcc.Address
|
||||
msg := stake.MsgCompleteRedelegate{
|
||||
DelegatorAddr: delegatorAddress,
|
||||
ValidatorSrcAddr: validatorSrcAddress,
|
||||
ValidatorDstAddr: validatorDstAddress,
|
||||
}
|
||||
if msg.ValidateBasic() != nil {
|
||||
return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
||||
}
|
||||
ctx, write := ctx.CacheContext()
|
||||
result := handler(ctx, msg)
|
||||
if result.IsOK() {
|
||||
write()
|
||||
}
|
||||
event(fmt.Sprintf("stake/MsgCompleteRedelegate/%v", result.IsOK()))
|
||||
action = fmt.Sprintf("TestMsgCompleteRedelegate: ok %v, msg %s", result.IsOK(), msg.GetSignBytes())
|
||||
return action, nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Setup
|
||||
// nolint: errcheck
|
||||
func Setup(mapp *mock.App, k stake.Keeper) simulation.RandSetup {
|
||||
|
|
|
@ -49,9 +49,7 @@ func TestStakeWithRandomMessages(t *testing.T) {
|
|||
{5, SimulateMsgEditValidator(stakeKeeper)},
|
||||
{15, SimulateMsgDelegate(mapper, stakeKeeper)},
|
||||
{10, SimulateMsgBeginUnbonding(mapper, stakeKeeper)},
|
||||
{3, SimulateMsgCompleteUnbonding(stakeKeeper)},
|
||||
{10, SimulateMsgBeginRedelegate(mapper, stakeKeeper)},
|
||||
{3, SimulateMsgCompleteRedelegate(stakeKeeper)},
|
||||
}, []simulation.RandSetup{
|
||||
Setup(mapp, stakeKeeper),
|
||||
}, []simulation.Invariant{
|
||||
|
|
|
@ -9,27 +9,25 @@ import (
|
|||
)
|
||||
|
||||
type (
|
||||
Keeper = keeper.Keeper
|
||||
Validator = types.Validator
|
||||
Description = types.Description
|
||||
Commission = types.Commission
|
||||
Delegation = types.Delegation
|
||||
DelegationSummary = types.DelegationSummary
|
||||
UnbondingDelegation = types.UnbondingDelegation
|
||||
Redelegation = types.Redelegation
|
||||
Params = types.Params
|
||||
Pool = types.Pool
|
||||
MsgCreateValidator = types.MsgCreateValidator
|
||||
MsgEditValidator = types.MsgEditValidator
|
||||
MsgDelegate = types.MsgDelegate
|
||||
MsgBeginUnbonding = types.MsgBeginUnbonding
|
||||
MsgCompleteUnbonding = types.MsgCompleteUnbonding
|
||||
MsgBeginRedelegate = types.MsgBeginRedelegate
|
||||
MsgCompleteRedelegate = types.MsgCompleteRedelegate
|
||||
GenesisState = types.GenesisState
|
||||
QueryDelegatorParams = querier.QueryDelegatorParams
|
||||
QueryValidatorParams = querier.QueryValidatorParams
|
||||
QueryBondsParams = querier.QueryBondsParams
|
||||
Keeper = keeper.Keeper
|
||||
Validator = types.Validator
|
||||
Description = types.Description
|
||||
Commission = types.Commission
|
||||
Delegation = types.Delegation
|
||||
DelegationSummary = types.DelegationSummary
|
||||
UnbondingDelegation = types.UnbondingDelegation
|
||||
Redelegation = types.Redelegation
|
||||
Params = types.Params
|
||||
Pool = types.Pool
|
||||
MsgCreateValidator = types.MsgCreateValidator
|
||||
MsgEditValidator = types.MsgEditValidator
|
||||
MsgDelegate = types.MsgDelegate
|
||||
MsgBeginUnbonding = types.MsgBeginUnbonding
|
||||
MsgBeginRedelegate = types.MsgBeginRedelegate
|
||||
GenesisState = types.GenesisState
|
||||
QueryDelegatorParams = querier.QueryDelegatorParams
|
||||
QueryValidatorParams = querier.QueryValidatorParams
|
||||
QueryBondsParams = querier.QueryBondsParams
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -76,9 +74,7 @@ var (
|
|||
NewMsgEditValidator = types.NewMsgEditValidator
|
||||
NewMsgDelegate = types.NewMsgDelegate
|
||||
NewMsgBeginUnbonding = types.NewMsgBeginUnbonding
|
||||
NewMsgCompleteUnbonding = types.NewMsgCompleteUnbonding
|
||||
NewMsgBeginRedelegate = types.NewMsgBeginRedelegate
|
||||
NewMsgCompleteRedelegate = types.NewMsgCompleteRedelegate
|
||||
|
||||
NewQuerier = querier.NewQuerier
|
||||
)
|
||||
|
|
|
@ -20,4 +20,5 @@ var (
|
|||
Delegator = sdk.TagDelegator
|
||||
Moniker = "moniker"
|
||||
Identity = "identity"
|
||||
EndTime = "end-time"
|
||||
)
|
||||
|
|
|
@ -10,9 +10,7 @@ func RegisterCodec(cdc *codec.Codec) {
|
|||
cdc.RegisterConcrete(MsgEditValidator{}, "cosmos-sdk/MsgEditValidator", nil)
|
||||
cdc.RegisterConcrete(MsgDelegate{}, "cosmos-sdk/MsgDelegate", nil)
|
||||
cdc.RegisterConcrete(MsgBeginUnbonding{}, "cosmos-sdk/BeginUnbonding", nil)
|
||||
cdc.RegisterConcrete(MsgCompleteUnbonding{}, "cosmos-sdk/CompleteUnbonding", nil)
|
||||
cdc.RegisterConcrete(MsgBeginRedelegate{}, "cosmos-sdk/BeginRedelegate", nil)
|
||||
cdc.RegisterConcrete(MsgCompleteRedelegate{}, "cosmos-sdk/CompleteRedelegate", nil)
|
||||
}
|
||||
|
||||
// generic sealed codec to be used throughout sdk
|
||||
|
|
|
@ -9,6 +9,23 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// DVPair is struct that just has a delegator-validator pair with no other data.
|
||||
// It is intended to be used as a marshalable pointer. For example, a DVPair can be used to construct the
|
||||
// key to getting an UnbondingDelegation from state.
|
||||
type DVPair struct {
|
||||
DelegatorAddr sdk.AccAddress
|
||||
ValidatorAddr sdk.ValAddress
|
||||
}
|
||||
|
||||
// DVVTriplet is struct that just has a delegator-validator-validator triplet with no other data.
|
||||
// It is intended to be used as a marshalable pointer. For example, a DVVTriplet can be used to construct the
|
||||
// key to getting a Redelegation from state.
|
||||
type DVVTriplet struct {
|
||||
DelegatorAddr sdk.AccAddress
|
||||
ValidatorSrcAddr sdk.ValAddress
|
||||
ValidatorDstAddr sdk.ValAddress
|
||||
}
|
||||
|
||||
// Delegation represents the bond with tokens held by an account. It is
|
||||
// owned by one delegator, and is associated with the voting power of one
|
||||
// pubKey.
|
||||
|
|
|
@ -12,8 +12,6 @@ const MsgType = "stake"
|
|||
|
||||
// Verify interface at compile time
|
||||
var _, _, _ sdk.Msg = &MsgCreateValidator{}, &MsgEditValidator{}, &MsgDelegate{}
|
||||
var _, _ sdk.Msg = &MsgBeginUnbonding{}, &MsgCompleteUnbonding{}
|
||||
var _, _ sdk.Msg = &MsgBeginRedelegate{}, &MsgCompleteRedelegate{}
|
||||
|
||||
//______________________________________________________________________
|
||||
|
||||
|
@ -276,51 +274,6 @@ func (msg MsgBeginRedelegate) ValidateBasic() sdk.Error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// MsgDelegate - struct for bonding transactions
|
||||
type MsgCompleteRedelegate struct {
|
||||
DelegatorAddr sdk.AccAddress `json:"delegator_addr"`
|
||||
ValidatorSrcAddr sdk.ValAddress `json:"validator_source_addr"`
|
||||
ValidatorDstAddr sdk.ValAddress `json:"validator_destination_addr"`
|
||||
}
|
||||
|
||||
func NewMsgCompleteRedelegate(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) MsgCompleteRedelegate {
|
||||
return MsgCompleteRedelegate{
|
||||
DelegatorAddr: delAddr,
|
||||
ValidatorSrcAddr: valSrcAddr,
|
||||
ValidatorDstAddr: valDstAddr,
|
||||
}
|
||||
}
|
||||
|
||||
//nolint
|
||||
func (msg MsgCompleteRedelegate) Type() string { return MsgType }
|
||||
func (msg MsgCompleteRedelegate) Name() string { return "complete_redelegate" }
|
||||
func (msg MsgCompleteRedelegate) GetSigners() []sdk.AccAddress {
|
||||
return []sdk.AccAddress{msg.DelegatorAddr}
|
||||
}
|
||||
|
||||
// get the bytes for the message signer to sign on
|
||||
func (msg MsgCompleteRedelegate) GetSignBytes() []byte {
|
||||
b, err := MsgCdc.MarshalJSON(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
||||
// quick validity check
|
||||
func (msg MsgCompleteRedelegate) ValidateBasic() sdk.Error {
|
||||
if msg.DelegatorAddr == nil {
|
||||
return ErrNilDelegatorAddr(DefaultCodespace)
|
||||
}
|
||||
if msg.ValidatorSrcAddr == nil {
|
||||
return ErrNilValidatorAddr(DefaultCodespace)
|
||||
}
|
||||
if msg.ValidatorDstAddr == nil {
|
||||
return ErrNilValidatorAddr(DefaultCodespace)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//______________________________________________________________________
|
||||
|
||||
// MsgBeginUnbonding - struct for unbonding transactions
|
||||
|
@ -373,43 +326,3 @@ func (msg MsgBeginUnbonding) ValidateBasic() sdk.Error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MsgCompleteUnbonding - struct for unbonding transactions
|
||||
type MsgCompleteUnbonding struct {
|
||||
DelegatorAddr sdk.AccAddress `json:"delegator_addr"`
|
||||
ValidatorAddr sdk.ValAddress `json:"validator_addr"`
|
||||
}
|
||||
|
||||
func NewMsgCompleteUnbonding(delAddr sdk.AccAddress, valAddr sdk.ValAddress) MsgCompleteUnbonding {
|
||||
return MsgCompleteUnbonding{
|
||||
DelegatorAddr: delAddr,
|
||||
ValidatorAddr: valAddr,
|
||||
}
|
||||
}
|
||||
|
||||
//nolint
|
||||
func (msg MsgCompleteUnbonding) Type() string { return MsgType }
|
||||
func (msg MsgCompleteUnbonding) Name() string { return "complete_unbonding" }
|
||||
func (msg MsgCompleteUnbonding) GetSigners() []sdk.AccAddress {
|
||||
return []sdk.AccAddress{msg.DelegatorAddr}
|
||||
}
|
||||
|
||||
// get the bytes for the message signer to sign on
|
||||
func (msg MsgCompleteUnbonding) GetSignBytes() []byte {
|
||||
b, err := MsgCdc.MarshalJSON(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
||||
// quick validity check
|
||||
func (msg MsgCompleteUnbonding) ValidateBasic() sdk.Error {
|
||||
if msg.DelegatorAddr == nil {
|
||||
return ErrNilDelegatorAddr(DefaultCodespace)
|
||||
}
|
||||
if msg.ValidatorAddr == nil {
|
||||
return ErrNilValidatorAddr(DefaultCodespace)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -177,31 +177,6 @@ func TestMsgBeginRedelegate(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// test ValidateBasic for MsgUnbond
|
||||
func TestMsgCompleteRedelegate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
delegatorAddr sdk.AccAddress
|
||||
validatorSrcAddr sdk.ValAddress
|
||||
validatorDstAddr sdk.ValAddress
|
||||
expectPass bool
|
||||
}{
|
||||
{"regular", sdk.AccAddress(addr1), addr2, addr3, true},
|
||||
{"empty delegator", sdk.AccAddress(emptyAddr), addr1, addr3, false},
|
||||
{"empty source validator", sdk.AccAddress(addr1), emptyAddr, addr3, false},
|
||||
{"empty destination validator", sdk.AccAddress(addr1), addr2, emptyAddr, false},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
msg := NewMsgCompleteRedelegate(tc.delegatorAddr, tc.validatorSrcAddr, tc.validatorDstAddr)
|
||||
if tc.expectPass {
|
||||
require.Nil(t, msg.ValidateBasic(), "test: %v", tc.name)
|
||||
} else {
|
||||
require.NotNil(t, msg.ValidateBasic(), "test: %v", tc.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// test ValidateBasic for MsgUnbond
|
||||
func TestMsgBeginUnbonding(t *testing.T) {
|
||||
tests := []struct {
|
||||
|
@ -227,26 +202,3 @@ func TestMsgBeginUnbonding(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// test ValidateBasic for MsgUnbond
|
||||
func TestMsgCompleteUnbonding(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
delegatorAddr sdk.AccAddress
|
||||
validatorAddr sdk.ValAddress
|
||||
expectPass bool
|
||||
}{
|
||||
{"regular", sdk.AccAddress(addr1), addr2, true},
|
||||
{"empty delegator", sdk.AccAddress(emptyAddr), addr1, false},
|
||||
{"empty validator", sdk.AccAddress(addr1), emptyAddr, false},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
msg := NewMsgCompleteUnbonding(tc.delegatorAddr, tc.validatorAddr)
|
||||
if tc.expectPass {
|
||||
require.Nil(t, msg.ValidateBasic(), "test: %v", tc.name)
|
||||
} else {
|
||||
require.NotNil(t, msg.ValidateBasic(), "test: %v", tc.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue