Merge PR #3803: Validator Creation Updates

This commit is contained in:
Alexander Bezobchuk 2019-03-05 11:55:46 -05:00 committed by Christopher Goes
parent 57fe79ffbf
commit 51c03aa6fe
11 changed files with 52 additions and 239 deletions

View File

@ -19,6 +19,11 @@
### Gaia
* [\#3789] Update validator creation flow:
* Remove `NewMsgCreateValidatorOnBehalfOf` and corresponding business logic
* Ensure the validator address equals the delegator address during
`MsgCreateValidator#ValidateBasic`
### SDK
* [\#3669] Ensure consistency in message naming, codec registration, and JSON

View File

@ -53,20 +53,19 @@ __Note__: If unspecified, `consensus_pubkey` will default to the output of `gaia
## Participate in genesis as a validator
__Note__: This section only concerns validators that want to be in the genesis file. If the chain you want to validate is already live, skip this section.
__Note__: This section only concerns validators that want to be in the genesis
file. If the chain you want to validate is already live, skip this section.
__Note__: `Gaia-9002` and `Game of stakes` will not use this process. They will be bootsrapped using Tendermint seed validators. You will just need to use the [create-validator](#create-your-validator) command in order to join as a validator for these networks.
__Note__: `Gaia-9002` and `Game of stakes` will not use this process. They will
be bootstrapped using validators operated by Tendermint. You will just need to use the
[create-validator](#create-your-validator) command in order to join as a validator
for these networks.
If you want to participate in genesis as a validator, you need to justify that you (or a delegator) have some stake at genesis, create one (or multiple) transaction to bond this stake to your validator address, and include this transaction in the genesis file.
If you want to participate in genesis as a validator, you need to justify that
you have some stake at genesis, create one (or multiple) transactions to bond this
stake to your validator address, and include this transaction in the genesis file.
We thus need to distinguish two cases:
- Case 1: You want to bond the initial stake from your validator's address.
- Case 2: You want to bond the initial stake from a delegator's address.
### Case 1: The initial stake comes from your validator's address
In this case, you will create a `gentx`:
You will need create a `gentx`:
```bash
gaiad gentx \
@ -78,46 +77,17 @@ gaiad gentx \
--name <key_name>
```
__Note__: This command automatically store your `gentx` in `~/.gaiad/config/gentx` for it to be processed at genesis.
__Note__: This command automatically store your `gentx` in `~/.gaiad/config/gentx`
for it to be processed at genesis.
::: tip
Consult `gaiad gentx --help` for more information on the flags defaults.
:::
A `gentx` is a JSON file carrying a self-delegation. All genesis transactions are collected by a `genesis coordinator` and validated against an initial `genesis.json`. Such initial `genesis.json` contains only a list of accounts and their coins. Once the transactions are processed, they are merged in the `genesis.json`'s `gentxs` field.
### Case 2: The initial stake comes from a delegator's address
In this case, you need both the signature of the validator and the delegator. Start by creating an unsigned `create-validator` transaction, and save it in a file called `unsignedValTx`:
```bash
gaiacli tx staking create-validator \
--amount=5STAKE \
--pubkey=$(gaiad tendermint show-validator) \
--moniker="choose a moniker" \
--chain-id=<chain_id> \
--from=<key_name> \
--commission-rate="0.10" \
--commission-max-rate="0.20" \
--commission-max-change-rate="0.01" \
--address-delegator="address of the delegator" \
--generate-only \
> unsignedValTx.json
```
Then, sign this `unsignedValTx` with your validator's private key, and save the output in a new file `signedValTx.json`:
```bash
gaiacli tx sign unsignedValTx.json --from=<validator_key_name> > signedValTx.json
```
Then, pass this file to the delegator, who needs to run the following command:
```bash
gaiacli tx sign signedValTx.json --from=<delegator_key_name> > gentx.json
```
This `gentx.json` needs to be included in the `~/.gaiad/config/gentx` folder on the validator's machine to be processed at genesis, just like in case 1 (except here it needs to be copied manually into the folder).
A `gentx` is a JSON file carrying a self-delegation. All genesis transactions are
collected by a `genesis coordinator` and validated against an initial `genesis.json`.
Such initial `genesis.json` contains only a list of accounts and their coins.
Once the transactions are processed, they are merged in the `genesis.json`'s `gentxs` field.
### Copy the Initial Genesis File and Process Genesis Transactions

View File

@ -57,13 +57,6 @@ __참고__: 이 문항은 제네시스 파일에 참가하려는 밸리데이터
밸리데이터로써 제네시스에 참가하고 싶으시다면 우선 본인(또는 위임자)가 stake를 보유하고 있다는 것을 증명해야 합니다. 스테이크를 검증인에게 본딩하는 하나 이상의 트랜잭션을 발생하신 후, 해당 트랜잭션을 제네시스 파일에 추가하시기 바랍니다.
우선 두가지의 케이스가 존재합니다:
- 경우 1: 본인 밸리데이터의 stake를 본딩(위임)한다.
- 경우 2: 타인(위임자)의 stake를 본딩한다.
### Case 1: 최초 위임이 밸리데이터 본인 주소에서 발생하는 경우
이런 경우에는 `gentx`를 생성하셔야 합니다:
```bash
@ -84,40 +77,6 @@ __참고__: 이 명령어는 제네시스에서의 처리를 위해 `gentx`를 `
`gentx`는 자체위임 정보가 포함된 JSON 파일입니다. 모든 제네시스 트랜잭셕은 `genesis coordinator`에 의하여 모아진 후 최초 `genesis.json`파일과 대치하여 검증합니다. 최초 `genesis.json`에는 계정 리스트와 각 계정이 보유하고 있는 코인 정보가 포함되어있습니다. 트랜잭션이 처리되었다면 해당 정보는 `genesis.json``gentx` 항목에 머지(merge)됩니다.
### Case 2: 최초 위임이 위임자(delegator) 주소에서 발생하는 경우
이런 경우에는 위임자와 검증인의 서명이 둘다 필요합니다. 우선 서명이 되지 않은 `create-validator` 트랜잭션을 생성하신 후 `unsignedValTx`라는 파일에 저장하십시오:
```bash
gaiacli tx staking create-validator \
--amount=5STAKE \
--pubkey=$(gaiad tendermint show-validator) \
--moniker="choose a moniker" \
--chain-id=<chain_id> \
--from=<key_name> \
--commission-rate="0.10" \
--commission-max-rate="0.20" \
--commission-max-change-rate="0.01" \
--address-delegator="address of the delegator" \
--generate-only \
> unsignedValTx.json
```
이제 해당 `unsignedValTx`를 밸리데이터의 프라이빗 키를 이용해 서명합니다. 서명이된 아웃풋을 `signedValTx.json`이라는 파일에 저장합니다:
```bash
gaiacli tx sign unsignedValTx.json --from=<validator_key_name> > signedValTx.json
```
이제 이 파일을 위임자에게 전달하세요. 위임인은 다음 명령어를 실행하면 됩니다:
```bash
gaiacli tx sign signedValTx.json --from=<delegator_key_name> > gentx.json
```
이 파일은 제네시스 절차에서 필요하기 때문에 Case 1과 동일하게 `gentx.json`은 밸리데이터 머신의 `~/.gaiad/config/gentx` 폴더에 포함되어야 합니다 (Case 2 에서는 직접 해당 파을을 이동해야 합니다).
### 제네시스 파일 복사, 제네시스 트랜잭션 처리하기
우선 `genesis.json`파일을 `gaiad`의 config 디렉토리로 가져옵니다.

View File

@ -85,12 +85,11 @@ var (
DefaultGenesisState = types.DefaultGenesisState
RegisterCodec = types.RegisterCodec
NewMsgCreateValidator = types.NewMsgCreateValidator
NewMsgCreateValidatorOnBehalfOf = types.NewMsgCreateValidatorOnBehalfOf
NewMsgEditValidator = types.NewMsgEditValidator
NewMsgDelegate = types.NewMsgDelegate
NewMsgUndelegate = types.NewMsgUndelegate
NewMsgBeginRedelegate = types.NewMsgBeginRedelegate
NewMsgCreateValidator = types.NewMsgCreateValidator
NewMsgEditValidator = types.NewMsgEditValidator
NewMsgDelegate = types.NewMsgDelegate
NewMsgUndelegate = types.NewMsgUndelegate
NewMsgBeginRedelegate = types.NewMsgBeginRedelegate
NewQuerier = querier.NewQuerier
NewQueryDelegatorParams = querier.NewQueryDelegatorParams

View File

@ -131,28 +131,13 @@ func TestStakingMsgs(t *testing.T) {
require.Equal(t, sdk.Bonded, validator.Status)
require.True(sdk.IntEq(t, bondTokens, validator.BondedTokens()))
// addr1 create validator on behalf of addr2
createValidatorMsgOnBehalfOf := NewMsgCreateValidatorOnBehalfOf(
addr1, sdk.ValAddress(addr2), priv2.PubKey(), bondCoin, description, commissionMsg, sdk.OneInt(),
)
mock.SignCheckDeliver(t, mApp.Cdc, mApp.BaseApp, []sdk.Msg{createValidatorMsgOnBehalfOf}, []uint64{0, 0}, []uint64{1, 0}, true, true, priv1, priv2)
mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin.Sub(bondCoin).Sub(bondCoin)})
mApp.BeginBlock(abci.RequestBeginBlock{})
validator = checkValidator(t, mApp, keeper, sdk.ValAddress(addr2), true)
require.Equal(t, sdk.ValAddress(addr2), validator.OperatorAddress)
require.Equal(t, sdk.Bonded, validator.Status)
require.True(sdk.IntEq(t, bondTokens, validator.Tokens))
// check the bond that should have been created as well
checkDelegation(t, mApp, keeper, addr1, sdk.ValAddress(addr1), true, bondTokens.ToDec())
// edit the validator
description = NewDescription("bar_moniker", "", "", "")
editValidatorMsg := NewMsgEditValidator(sdk.ValAddress(addr1), description, nil, nil)
mock.SignCheckDeliver(t, mApp.Cdc, mApp.BaseApp, []sdk.Msg{editValidatorMsg}, []uint64{0}, []uint64{2}, true, true, priv1)
mock.SignCheckDeliver(t, mApp.Cdc, mApp.BaseApp, []sdk.Msg{editValidatorMsg}, []uint64{0}, []uint64{1}, true, true, priv1)
validator = checkValidator(t, mApp, keeper, sdk.ValAddress(addr1), true)
require.Equal(t, description, validator.Description)
@ -160,13 +145,13 @@ func TestStakingMsgs(t *testing.T) {
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin})
delegateMsg := NewMsgDelegate(addr2, sdk.ValAddress(addr1), bondCoin)
mock.SignCheckDeliver(t, mApp.Cdc, mApp.BaseApp, []sdk.Msg{delegateMsg}, []uint64{0}, []uint64{1}, true, true, priv2)
mock.SignCheckDeliver(t, mApp.Cdc, mApp.BaseApp, []sdk.Msg{delegateMsg}, []uint64{0}, []uint64{0}, true, true, priv2)
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Sub(bondCoin)})
checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), true, bondTokens.ToDec())
// begin unbonding
beginUnbondingMsg := NewMsgUndelegate(addr2, sdk.ValAddress(addr1), bondTokens.ToDec())
mock.SignCheckDeliver(t, mApp.Cdc, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []uint64{0}, []uint64{2}, true, true, priv2)
mock.SignCheckDeliver(t, mApp.Cdc, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []uint64{0}, []uint64{1}, true, true, priv2)
// delegation should exist anymore
checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), false, sdk.Dec{})

View File

@ -8,7 +8,6 @@ import (
// nolint
const (
FlagAddressDelegator = "address-delegator"
FlagAddressValidator = "validator"
FlagAddressValidatorSrc = "addr-validator-source"
FlagAddressValidatorDst = "addr-validator-dest"
@ -67,7 +66,6 @@ func init() {
fsDescriptionEdit.String(FlagWebsite, types.DoNotModifyDesc, "The validator's (optional) website")
fsDescriptionEdit.String(FlagDetails, types.DoNotModifyDesc, "The validator's (optional) details")
fsValidator.String(FlagAddressValidator, "", "The Bech32 address of the validator")
fsDelegator.String(FlagAddressDelegator, "", "The Bech32 address of the delegator")
fsRedelegation.String(FlagAddressValidatorSrc, "", "The Bech32 address of the source validator")
fsRedelegation.String(FlagAddressValidatorDst, "", "The Bech32 address of the destination validator")
}

View File

@ -44,7 +44,7 @@ func GetCmdCreateValidator(cdc *codec.Codec) *cobra.Command {
cmd.Flags().AddFlagSet(fsDescriptionCreate)
cmd.Flags().AddFlagSet(FsCommissionCreate)
cmd.Flags().AddFlagSet(FsMinSelfDelegation)
cmd.Flags().AddFlagSet(fsDelegator)
cmd.Flags().String(FlagIP, "", fmt.Sprintf("The node's public IP. It takes effect only when used in combination with --%s", client.FlagGenerateOnly))
cmd.Flags().String(FlagNodeID, "", "The node's ID")
@ -259,23 +259,9 @@ func BuildCreateValidatorMsg(cliCtx context.CLIContext, txBldr authtxb.TxBuilder
return txBldr, nil, fmt.Errorf(staking.ErrMinSelfDelegationInvalid(staking.DefaultCodespace).Error())
}
delAddr := viper.GetString(FlagAddressDelegator)
var msg sdk.Msg
if delAddr != "" {
delAddr, err := sdk.AccAddressFromBech32(delAddr)
if err != nil {
return txBldr, nil, err
}
msg = staking.NewMsgCreateValidatorOnBehalfOf(
delAddr, sdk.ValAddress(valAddr), pk, amount, description, commissionMsg, minSelfDelegation,
)
} else {
msg = staking.NewMsgCreateValidator(
sdk.ValAddress(valAddr), pk, amount, description, commissionMsg, minSelfDelegation,
)
}
msg := staking.NewMsgCreateValidator(
sdk.ValAddress(valAddr), pk, amount, description, commissionMsg, minSelfDelegation,
)
if viper.GetBool(client.FlagGenerateOnly) {
ip := viper.GetString(FlagIP)
@ -284,5 +270,6 @@ func BuildCreateValidatorMsg(cliCtx context.CLIContext, txBldr authtxb.TxBuilder
txBldr = txBldr.WithMemo(fmt.Sprintf("%s@%s:26656", nodeID, ip))
}
}
return txBldr, msg, nil
}

View File

@ -178,38 +178,6 @@ func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) {
require.True(t, got.IsOK(), "%v", got)
}
func TestDuplicatesMsgCreateValidatorOnBehalfOf(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
validatorAddr := sdk.ValAddress(keep.Addrs[0])
delegatorAddr := keep.Addrs[1]
pk := keep.PKs[0]
valTokens := sdk.TokensFromTendermintPower(10)
msgCreateValidatorOnBehalfOf := NewTestMsgCreateValidatorOnBehalfOf(delegatorAddr, validatorAddr, pk, valTokens)
got := handleMsgCreateValidator(ctx, msgCreateValidatorOnBehalfOf, keeper)
require.True(t, got.IsOK(), "%v", got)
// must end-block
updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
require.Equal(t, 1, len(updates))
validator, found := keeper.GetValidator(ctx, validatorAddr)
require.True(t, found)
assert.Equal(t, sdk.Bonded, validator.Status)
assert.Equal(t, validatorAddr, validator.OperatorAddress)
assert.Equal(t, pk, validator.ConsPubKey)
assert.True(sdk.IntEq(t, valTokens, validator.Tokens))
assert.True(sdk.DecEq(t, valTokens.ToDec(), validator.DelegatorShares))
assert.Equal(t, Description{}, validator.Description)
// one validator cannot be created twice even from different delegator
msgCreateValidatorOnBehalfOf.DelegatorAddress = keep.Addrs[2]
msgCreateValidatorOnBehalfOf.PubKey = keep.PKs[1]
got = handleMsgCreateValidator(ctx, msgCreateValidatorOnBehalfOf, keeper)
require.False(t, got.IsOK(), "%v", got)
}
func TestLegacyValidatorDelegations(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, int64(1000))
setInstantUnbondPeriod(keeper, ctx)
@ -555,25 +523,27 @@ func TestMultipleMsgCreateValidator(t *testing.T) {
sdk.ValAddress(keep.Addrs[2]),
}
delegatorAddrs := []sdk.AccAddress{
keep.Addrs[3],
keep.Addrs[4],
keep.Addrs[5],
keep.Addrs[0],
keep.Addrs[1],
keep.Addrs[2],
}
// bond them all
for i, validatorAddr := range validatorAddrs {
valTokens := sdk.TokensFromTendermintPower(10)
msgCreateValidatorOnBehalfOf := NewTestMsgCreateValidatorOnBehalfOf(
delegatorAddrs[i], validatorAddr, keep.PKs[i], valTokens)
msgCreateValidatorOnBehalfOf := NewTestMsgCreateValidator(validatorAddr, keep.PKs[i], valTokens)
got := handleMsgCreateValidator(ctx, msgCreateValidatorOnBehalfOf, keeper)
require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got)
//Check that the account is bonded
// verify that the account is bonded
validators := keeper.GetValidators(ctx, 100)
require.Equal(t, (i + 1), len(validators))
val := validators[i]
balanceExpd := initTokens.Sub(valTokens)
balanceGot := accMapper.GetAccount(ctx, delegatorAddrs[i]).GetCoins().AmountOf(params.BondDenom)
require.Equal(t, i+1, len(validators), "expected %d validators got %d, validators: %v", i+1, len(validators), validators)
require.Equal(t, valTokens, val.DelegatorShares.RoundInt(), "expected %d shares, got %d", 10, val.DelegatorShares)
require.Equal(t, balanceExpd, balanceGot, "expected account to have %d, got %d", balanceExpd, balanceGot)

View File

@ -54,10 +54,3 @@ func NewTestMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amt sdk.
amount := sdk.NewCoin(sdk.DefaultBondDenom, amt)
return NewMsgDelegate(delAddr, valAddr, amount)
}
func NewTestMsgCreateValidatorOnBehalfOf(delAddr sdk.AccAddress, valAddr sdk.ValAddress,
valPubKey crypto.PubKey, amt sdk.Int) MsgCreateValidator {
amount := sdk.NewCoin(sdk.DefaultBondDenom, amt)
return NewMsgCreateValidatorOnBehalfOf(delAddr, valAddr, valPubKey, amount, Description{}, commissionMsg, sdk.OneInt())
}

View File

@ -42,23 +42,17 @@ type msgCreateValidatorJSON struct {
}
// Default way to create validator. Delegator address and validator address are the same
func NewMsgCreateValidator(valAddr sdk.ValAddress, pubkey crypto.PubKey,
selfDelegation sdk.Coin, description Description, commission CommissionMsg, minSelfDelegation sdk.Int) MsgCreateValidator {
func NewMsgCreateValidator(
valAddr sdk.ValAddress, pubKey crypto.PubKey, selfDelegation sdk.Coin,
description Description, commission CommissionMsg, minSelfDelegation sdk.Int,
) MsgCreateValidator {
return NewMsgCreateValidatorOnBehalfOf(
sdk.AccAddress(valAddr), valAddr, pubkey, selfDelegation, description, commission, minSelfDelegation,
)
}
// Creates validator msg by delegator address on behalf of validator address
func NewMsgCreateValidatorOnBehalfOf(delAddr sdk.AccAddress, valAddr sdk.ValAddress,
pubkey crypto.PubKey, value sdk.Coin, description Description, commission CommissionMsg, minSelfDelegation sdk.Int) MsgCreateValidator {
return MsgCreateValidator{
Description: description,
DelegatorAddress: delAddr,
DelegatorAddress: sdk.AccAddress(valAddr),
ValidatorAddress: valAddr,
PubKey: pubkey,
Value: value,
PubKey: pubKey,
Value: selfDelegation,
Commission: commission,
MinSelfDelegation: minSelfDelegation,
}
@ -133,6 +127,9 @@ func (msg MsgCreateValidator) ValidateBasic() sdk.Error {
if msg.ValidatorAddress.Empty() {
return ErrNilValidatorAddr(DefaultCodespace)
}
if !sdk.AccAddress(msg.ValidatorAddress).Equals(msg.DelegatorAddress) {
return ErrBadValidatorAddr(DefaultCodespace)
}
if msg.Value.Amount.LTE(sdk.ZeroInt()) {
return ErrBadDelegationAmount(DefaultCodespace)
}

View File

@ -4,7 +4,6 @@ import (
"testing"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -78,55 +77,6 @@ func TestMsgEditValidator(t *testing.T) {
}
}
// test ValidateBasic and GetSigners for MsgCreateValidatorOnBehalfOf
func TestMsgCreateValidatorOnBehalfOf(t *testing.T) {
commission1 := NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec())
commission2 := NewCommissionMsg(sdk.NewDec(5), sdk.NewDec(5), sdk.NewDec(5))
tests := []struct {
name, moniker, identity, website, details string
commissionMsg CommissionMsg
minSelfDelegation sdk.Int
delegatorAddr sdk.AccAddress
validatorAddr sdk.ValAddress
validatorPubKey crypto.PubKey
bond sdk.Coin
expectPass bool
}{
{"basic good", "a", "b", "c", "d", commission2, sdk.OneInt(), sdk.AccAddress(addr1), addr2, pk2, coinPos, true},
{"partial description", "", "", "c", "", commission2, sdk.OneInt(), sdk.AccAddress(addr1), addr2, pk2, coinPos, true},
{"empty description", "", "", "", "", commission1, sdk.OneInt(), sdk.AccAddress(addr1), addr2, pk2, coinPos, false},
{"empty delegator address", "a", "b", "c", "d", commission1, sdk.OneInt(), sdk.AccAddress(emptyAddr), addr2, pk2, coinPos, false},
{"empty validator address", "a", "b", "c", "d", commission2, sdk.OneInt(), sdk.AccAddress(addr1), emptyAddr, pk2, coinPos, false},
{"empty pubkey", "a", "b", "c", "d", commission1, sdk.OneInt(), sdk.AccAddress(addr1), addr2, emptyPubkey, coinPos, true},
{"empty bond", "a", "b", "c", "d", commission2, sdk.OneInt(), sdk.AccAddress(addr1), addr2, pk2, coinZero, false},
{"zero min self delegation", "a", "b", "c", "d", commission2, sdk.ZeroInt(), sdk.AccAddress(addr1), addr2, pk2, coinPos, false},
{"negative min self delegation", "", "", "c", "", commission2, sdk.NewInt(-1), sdk.AccAddress(addr1), addr2, pk2, coinPos, false},
{"delegation less than min self delegation", "a", "b", "c", "d", commission2, coinPos.Amount.Add(sdk.OneInt()), sdk.AccAddress(addr1), addr2, pk2, coinPos, false},
}
for _, tc := range tests {
description := NewDescription(tc.moniker, tc.identity, tc.website, tc.details)
msg := NewMsgCreateValidatorOnBehalfOf(
tc.delegatorAddr, tc.validatorAddr, tc.validatorPubKey, tc.bond, description, tc.commissionMsg, tc.minSelfDelegation,
)
if tc.expectPass {
require.Nil(t, msg.ValidateBasic(), "test: %v", tc.name)
} else {
require.NotNil(t, msg.ValidateBasic(), "test: %v", tc.name)
}
}
msg := NewMsgCreateValidator(addr1, pk1, coinPos, Description{}, CommissionMsg{}, sdk.OneInt())
addrs := msg.GetSigners()
require.Equal(t, []sdk.AccAddress{sdk.AccAddress(addr1)}, addrs, "Signers on default msg is wrong")
msg = NewMsgCreateValidatorOnBehalfOf(sdk.AccAddress(addr2), addr1, pk1, coinPos, Description{}, CommissionMsg{}, sdk.OneInt())
addrs = msg.GetSigners()
require.Equal(t, []sdk.AccAddress{sdk.AccAddress(addr2), sdk.AccAddress(addr1)}, addrs, "Signers for onbehalfof msg is wrong")
}
// test ValidateBasic for MsgDelegate
func TestMsgDelegate(t *testing.T) {
tests := []struct {