Skip to content

Commit

Permalink
unbonding redelegation queue
Browse files Browse the repository at this point in the history
  • Loading branch information
sunnya97 committed Sep 26, 2018
1 parent 7d5bc45 commit 766dc94
Show file tree
Hide file tree
Showing 22 changed files with 297 additions and 549 deletions.
1 change: 1 addition & 0 deletions PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ BREAKING CHANGES
* [x/stake] [#1013] TendermintUpdates now uses transient store
* [x/gov] [#2195] Governance uses BFT Time
* [x/gov] \#2256 Removed slashing for governance non-voting validators
* [x/stake] \#2393 Removed `CompleteUnbonding` and `CompleteRedelegation` Msg types, and instead added unbonding/redelegation queues to endblocker

* SDK
* [core] [\#1807](https://github.com/cosmos/cosmos-sdk/issues/1807) Switch from use of rational to decimal
Expand Down
2 changes: 0 additions & 2 deletions cmd/gaia/app/sim_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)},
}
}
Expand Down
31 changes: 31 additions & 0 deletions docs/spec/staking/end_block.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,34 @@ EndBlock() ValidatorSetChanges
ClearTendermintUpdates()
return vsc
```


## CompleteUnbonding

Complete the unbonding and transfer the coins to the delegate. Perform any
slashing that occurred during the unbonding period.

```golang
unbondingQueue(currTime time.Time):
for all unbondings whose CompleteTime < currTime:
validator = GetValidator(unbonding.ValidatorAddr)
returnTokens = ExpectedTokens * unbonding.startSlashRatio/validator.SlashRatio
AddCoins(unbonding.DelegatorAddr, returnTokens)
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.

```golang
redelegationQueue(currTime time.Time):
for all redelegations whose CompleteTime < currTime:
removeRedelegation(redelegation)
return
```
43 changes: 0 additions & 43 deletions docs/spec/staking/transactions.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ corresponding updates to the state. Transactions:
* TxEditValidator
* TxDelegation
* TxStartUnbonding
* TxCompleteUnbonding
* TxRedelegate
* TxCompleteRedelegation

Other important state changes:

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions types/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package types
import (
"context"
"sync"
"time"

"github.com/golang/protobuf/proto"

Expand Down Expand Up @@ -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)
}
Expand Down
7 changes: 7 additions & 0 deletions types/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 2 additions & 3 deletions x/slashing/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,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)
Expand Down
81 changes: 0 additions & 81 deletions x/stake/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,6 @@ func GetCmdRedelegate(storeName string, cdc *codec.Codec) *cobra.Command {
cmd.AddCommand(
client.PostCommands(
GetCmdBeginRedelegate(storeName, cdc),
GetCmdCompleteRedelegate(cdc),
)...)

return cmd
Expand Down Expand Up @@ -275,48 +274,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).
WithLogger(os.Stdout).
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{
Expand All @@ -327,7 +284,6 @@ func GetCmdUnbond(storeName string, cdc *codec.Codec) *cobra.Command {
cmd.AddCommand(
client.PostCommands(
GetCmdBeginUnbonding(storeName, cdc),
GetCmdCompleteUnbonding(cdc),
)...)

return cmd
Expand Down Expand Up @@ -381,40 +337,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).
WithLogger(os.Stdout).
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
}
84 changes: 5 additions & 79 deletions x/stake/client/rest/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
}
)

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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())
Expand Down
Loading

0 comments on commit 766dc94

Please sign in to comment.