Merge branch 'develop' into cwgoes/nextvalset
This commit is contained in:
commit
4814ae4df5
|
@ -164,13 +164,12 @@
|
|||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c0d19ab64b32ce9fe5cf4ddceba78d5bc9807f0016db6b1183599da3dcc24d10"
|
||||
digest = "1:ea40c24cdbacd054a6ae9de03e62c5f252479b96c716375aace5c120d68647c8"
|
||||
name = "github.com/hashicorp/hcl"
|
||||
packages = [
|
||||
".",
|
||||
"hcl/ast",
|
||||
"hcl/parser",
|
||||
"hcl/printer",
|
||||
"hcl/scanner",
|
||||
"hcl/strconv",
|
||||
"hcl/token",
|
||||
|
@ -447,7 +446,7 @@
|
|||
version = "v0.11.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f4fcc1a4dbe079b200556ca26c1ff1dacf23712125b9c265d8f02c0dbc318f39"
|
||||
digest = "1:a69eebd15b05045ffdb10a984e001fadc5666f74383de3d2a9ee5862ee99cfdc"
|
||||
name = "github.com/tendermint/tendermint"
|
||||
packages = [
|
||||
"abci/client",
|
||||
|
@ -478,6 +477,7 @@
|
|||
"libs/clist",
|
||||
"libs/common",
|
||||
"libs/db",
|
||||
"libs/errors",
|
||||
"libs/events",
|
||||
"libs/flowrate",
|
||||
"libs/log",
|
||||
|
@ -512,8 +512,8 @@
|
|||
"version",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "d419fffe18531317c28c29a292ad7d253f6cafdf"
|
||||
version = "v0.24.0"
|
||||
revision = "0c9c3292c918617624f6f3fbcd95eceade18bcd5"
|
||||
version = "v0.25.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7886f86064faff6f8d08a3eb0e8c773648ff5a2e27730831e2bfbf07467f6666"
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
|
||||
[[override]]
|
||||
name = "github.com/tendermint/tendermint"
|
||||
version = "=0.24.0"
|
||||
version = "=0.25.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/bartekn/go-bip39"
|
||||
|
|
12
PENDING.md
12
PENDING.md
|
@ -43,6 +43,7 @@ BREAKING CHANGES
|
|||
* [x/gov] \#2256 Removed slashing for governance non-voting validators
|
||||
* [simulation] \#2162 Added back correct supply invariants
|
||||
* [x/slashing] \#2430 Simulate more slashes, check if validator is jailed before jailing
|
||||
* [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
|
||||
|
@ -70,6 +71,16 @@ BREAKING CHANGES
|
|||
* [x/stake] \#2394 Split up UpdateValidator into distinct state transitions applied only in EndBlock
|
||||
|
||||
* Tendermint
|
||||
* Update tendermint version from v0.23.0 to v0.25.0, notable changes
|
||||
* Mempool now won't build too large blocks, or too computationally expensive blocks
|
||||
* Maximum tx sizes and gas are now removed, and are implicitly the blocks maximums
|
||||
* ABCI validators no longer send the pubkey. The pubkey is only sent in validator updates
|
||||
* Validator set changes are now delayed by one block
|
||||
* Block header now includes the next validator sets hash
|
||||
* BFT time is implemented
|
||||
* Secp256k1 signature format has changed
|
||||
* There is now a threshold multisig format
|
||||
* See the [tendermint changelog](https://github.com/tendermint/tendermint/blob/master/CHANGELOG.md) for other changes.
|
||||
|
||||
FEATURES
|
||||
|
||||
|
@ -136,6 +147,7 @@ IMPROVEMENTS
|
|||
* [x/stake] Improve speed of GetValidator, which was shown to be a performance bottleneck. [#2046](https://github.com/tendermint/tendermint/pull/2200)
|
||||
* [x/stake] \#2435 Improve memory efficiency of getting the various store keys
|
||||
* [genesis] \#2229 Ensure that there are no duplicate accounts or validators in the genesis state.
|
||||
* [genesis] \#2450 Validate staking genesis parameters.
|
||||
* Add SDK validation to `config.toml` (namely disabling `create_empty_blocks`) \#1571
|
||||
* \#1941(https://github.com/cosmos/cosmos-sdk/issues/1941) Version is now inferred via `git describe --tags`.
|
||||
* [x/distribution] \#1671 add distribution types and tests
|
||||
|
|
|
@ -13,7 +13,6 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
|
@ -242,29 +241,13 @@ func GaiaValidateGenesisState(genesisState GenesisState) (err error) {
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = validateGenesisStateValidators(genesisState.StakeData.Validators)
|
||||
err = stake.ValidateGenesis(genesisState.StakeData)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func validateGenesisStateValidators(validators []stakeTypes.Validator) (err error) {
|
||||
addrMap := make(map[string]bool, len(validators))
|
||||
for i := 0; i < len(validators); i++ {
|
||||
val := validators[i]
|
||||
strKey := string(val.ConsPubKey.Bytes())
|
||||
if _, ok := addrMap[strKey]; ok {
|
||||
return fmt.Errorf("Duplicate validator in genesis state: moniker %v, Address %v", val.Description.Moniker, val.ConsAddress())
|
||||
}
|
||||
if val.Jailed && val.Status == sdk.Bonded {
|
||||
return fmt.Errorf("Validator is bonded and jailed in genesis state: moniker %v, Address %v", val.Description.Moniker, val.ConsAddress())
|
||||
}
|
||||
addrMap[strKey] = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Ensures that there are no duplicate accounts in the genesis state,
|
||||
func validateGenesisStateAccounts(accs []GenesisAccount) (err error) {
|
||||
addrMap := make(map[string]bool, len(accs))
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
@ -190,7 +197,7 @@ func (c Context) WithConsensusParams(params *abci.ConsensusParams) Context {
|
|||
return c
|
||||
}
|
||||
return c.withValue(contextKeyConsensusParams, params).
|
||||
WithGasMeter(NewGasMeter(params.TxSize.MaxGas))
|
||||
WithGasMeter(NewGasMeter(params.BlockSize.MaxGas))
|
||||
}
|
||||
|
||||
func (c Context) WithChainID(chainID string) Context { return c.withValue(contextKeyChainID, chainID) }
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package stake
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
|
@ -81,3 +83,58 @@ func WriteValidators(ctx sdk.Context, keeper Keeper) (vals []tmtypes.GenesisVali
|
|||
|
||||
return
|
||||
}
|
||||
|
||||
// ValidateGenesis validates the provided staking genesis state to ensure the
|
||||
// expected invariants holds. (i.e. params in correct bounds, no duplicate validators)
|
||||
func ValidateGenesis(data types.GenesisState) error {
|
||||
err := validateGenesisStateValidators(data.Validators)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = validateParams(data.Params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateParams(params types.Params) error {
|
||||
if params.GoalBonded.LTE(sdk.ZeroDec()) {
|
||||
bondedPercent := params.GoalBonded.MulInt(sdk.NewInt(100)).String()
|
||||
return fmt.Errorf("staking parameter GoalBonded should be positive, instead got %s percent", bondedPercent)
|
||||
}
|
||||
if params.GoalBonded.GT(sdk.OneDec()) {
|
||||
bondedPercent := params.GoalBonded.MulInt(sdk.NewInt(100)).String()
|
||||
return fmt.Errorf("staking parameter GoalBonded should be less than 100 percent, instead got %s percent", bondedPercent)
|
||||
}
|
||||
if params.BondDenom == "" {
|
||||
return fmt.Errorf("staking parameter BondDenom can't be an empty string")
|
||||
}
|
||||
if params.InflationMax.LT(params.InflationMin) {
|
||||
return fmt.Errorf("staking parameter Max inflation must be greater than or equal to min inflation")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateGenesisStateValidators(validators []types.Validator) (err error) {
|
||||
addrMap := make(map[string]bool, len(validators))
|
||||
for i := 0; i < len(validators); i++ {
|
||||
val := validators[i]
|
||||
strKey := string(val.ConsPubKey.Bytes())
|
||||
if _, ok := addrMap[strKey]; ok {
|
||||
return fmt.Errorf("duplicate validator in genesis state: moniker %v, Address %v", val.Description.Moniker, val.ConsAddress())
|
||||
}
|
||||
if val.Jailed && val.Status == sdk.Bonded {
|
||||
return fmt.Errorf("validator is bonded and jailed in genesis state: moniker %v, Address %v", val.Description.Moniker, val.ConsAddress())
|
||||
}
|
||||
if val.Tokens.IsZero() {
|
||||
return fmt.Errorf("genesis validator cannot have zero pool shares, validator: %v", val)
|
||||
}
|
||||
if val.DelegatorShares.IsZero() {
|
||||
return fmt.Errorf("genesis validator cannot have zero delegator shares, validator: %v", val)
|
||||
}
|
||||
addrMap[strKey] = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -4,13 +4,15 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
keep "github.com/cosmos/cosmos-sdk/x/stake/keeper"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
)
|
||||
|
||||
func TestInitGenesis(t *testing.T) {
|
||||
|
@ -105,3 +107,59 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) {
|
|||
|
||||
require.Equal(t, abcivals, vals)
|
||||
}
|
||||
|
||||
func TestValidateGenesis(t *testing.T) {
|
||||
genValidators1 := make([]types.Validator, 1, 5)
|
||||
pk := ed25519.GenPrivKey().PubKey()
|
||||
genValidators1[0] = types.NewValidator(sdk.ValAddress(pk.Address()), pk, types.NewDescription("", "", "", ""))
|
||||
genValidators1[0].Tokens = sdk.OneDec()
|
||||
genValidators1[0].DelegatorShares = sdk.OneDec()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
mutate func(*types.GenesisState)
|
||||
wantErr bool
|
||||
}{
|
||||
{"default", func(*types.GenesisState) {}, false},
|
||||
// validate params
|
||||
{"200% goalbonded", func(data *types.GenesisState) { (*data).Params.GoalBonded = sdk.OneDec().Add(sdk.OneDec()) }, true},
|
||||
{"-67% goalbonded", func(data *types.GenesisState) { (*data).Params.GoalBonded = sdk.OneDec().Neg() }, true},
|
||||
{"no bond denom", func(data *types.GenesisState) { (*data).Params.BondDenom = "" }, true},
|
||||
{"min inflation > max inflation", func(data *types.GenesisState) {
|
||||
(*data).Params.InflationMin = (*data).Params.InflationMax.Add(sdk.OneDec())
|
||||
}, true},
|
||||
{"min inflation = max inflation", func(data *types.GenesisState) {
|
||||
(*data).Params.InflationMax = (*data).Params.InflationMin
|
||||
}, false},
|
||||
// validate genesis validators
|
||||
{"duplicate validator", func(data *types.GenesisState) {
|
||||
(*data).Validators = genValidators1
|
||||
(*data).Validators = append((*data).Validators, genValidators1[0])
|
||||
}, true},
|
||||
{"no pool shares", func(data *types.GenesisState) {
|
||||
(*data).Validators = genValidators1
|
||||
(*data).Validators[0].Tokens = sdk.ZeroDec()
|
||||
}, true},
|
||||
{"no delegator shares", func(data *types.GenesisState) {
|
||||
(*data).Validators = genValidators1
|
||||
(*data).Validators[0].DelegatorShares = sdk.ZeroDec()
|
||||
}, true},
|
||||
{"jailed and bonded validator", func(data *types.GenesisState) {
|
||||
(*data).Validators = genValidators1
|
||||
(*data).Validators[0].Jailed = true
|
||||
(*data).Validators[0].Status = sdk.Bonded
|
||||
}, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
genesisState := types.DefaultGenesisState()
|
||||
tt.mutate(&genesisState)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, ValidateGenesis(genesisState))
|
||||
} else {
|
||||
assert.NoError(t, ValidateGenesis(genesisState))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,12 +12,10 @@ const MsgType = "stake"
|
|||
|
||||
// Verify interface at compile time
|
||||
var _, _, _ sdk.Msg = &MsgCreateValidator{}, &MsgEditValidator{}, &MsgDelegate{}
|
||||
var _, _ sdk.Msg = &MsgBeginUnbonding{}, &MsgCompleteUnbonding{}
|
||||
var _, _ sdk.Msg = &MsgBeginRedelegate{}, &MsgCompleteRedelegate{}
|
||||
|
||||
//______________________________________________________________________
|
||||
|
||||
// MsgCreateValidator - struct for unbonding transactions
|
||||
// MsgCreateValidator - struct for bonding transactions
|
||||
type MsgCreateValidator struct {
|
||||
Description
|
||||
Commission CommissionMsg
|
||||
|
@ -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