Skip to content

Commit

Permalink
Merge pull request #1600: Friend can create validator and delegate on…
Browse files Browse the repository at this point in the history
… behalf of genesis validator

* Added msg and handling for surrogate create validator

* changelog and error fix

* fix changelog

* Remove unnecessary msg by combining into CreateValidator

* Refactor

* Appease linter

* Added onbehalfof functionality in client

* fmt

* Added gaia onbehalfof test

* Update test for onbehalfof validator creation

* fix test

* Fix flag error

* Add app test

* fmt

* Fixed signer for onbehalfof createvalidator

* Fix error msg

* Simplify test

* fmt
  • Loading branch information
AdityaSripal authored and rigelrozanski committed Jul 11, 2018
1 parent 9afb894 commit b195c55
Show file tree
Hide file tree
Showing 11 changed files with 180 additions and 53 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ FEATURES
* [tests] created a randomized testing framework.
- Currently bank has limited functionality in the framework
- Auth has its invariants checked within the framework
* [x/stake] Allow validator to be created with starting delegation by a third-party delegator on behalf of validator.
* [tests] Add WaitForNextNBlocksTM helper method
* [keys] New keys now have 24 word recovery keys, for heightened security

Expand Down
2 changes: 1 addition & 1 deletion client/lcd/lcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,7 @@ func doDelegate(t *testing.T, port, seed, name, password string, delegatorAddr,
{
"delegator_addr": "%s",
"validator_addr": "%s",
"bond": { "denom": "%s", "amount": "60" }
"delegation": { "denom": "%s", "amount": "60" }
}
],
"begin_unbondings": [],
Expand Down
9 changes: 5 additions & 4 deletions x/slashing/test_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,10 @@ func testAddr(addr string) sdk.AccAddress {

func newTestMsgCreateValidator(address sdk.AccAddress, pubKey crypto.PubKey, amt sdk.Int) stake.MsgCreateValidator {
return stake.MsgCreateValidator{
Description: stake.Description{},
ValidatorAddr: address,
PubKey: pubKey,
SelfDelegation: sdk.Coin{"steak", amt},
Description: stake.Description{},
DelegatorAddr: address,
ValidatorAddr: address,
PubKey: pubKey,
Delegation: sdk.Coin{"steak", amt},
}
}
20 changes: 16 additions & 4 deletions x/stake/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func checkValidator(t *testing.T, mapp *mock.App, keeper Keeper,
addr sdk.AccAddress, expFound bool) Validator {

ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{})
validator, found := keeper.GetValidator(ctxCheck, addr1)
validator, found := keeper.GetValidator(ctxCheck, addr)

require.Equal(t, expFound, found)
return validator
Expand Down Expand Up @@ -138,28 +138,40 @@ func TestStakeMsgs(t *testing.T) {
require.Equal(t, sdk.Bonded, validator.Status())
require.True(sdk.RatEq(t, sdk.NewRat(10), validator.PoolShares.Bonded()))

// addr1 create validator on behalf of addr2
createValidatorMsgOnBehalfOf := NewMsgCreateValidatorOnBehalfOf(addr1, addr2, priv2.PubKey(), bondCoin, description)

mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsgOnBehalfOf}, []int64{0, 1}, []int64{1, 0}, true, priv1, priv2)
mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin.Minus(bondCoin).Minus(bondCoin)})
mApp.BeginBlock(abci.RequestBeginBlock{})

validator = checkValidator(t, mApp, keeper, addr2, true)
require.Equal(t, addr2, validator.Owner)
require.Equal(t, sdk.Bonded, validator.Status())
require.True(sdk.RatEq(t, sdk.NewRat(10), validator.PoolShares.Bonded()))

// check the bond that should have been created as well
checkDelegation(t, mApp, keeper, addr1, addr1, true, sdk.NewRat(10))

// edit the validator
description = NewDescription("bar_moniker", "", "", "")
editValidatorMsg := NewMsgEditValidator(addr1, description)

mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{editValidatorMsg}, []int64{0}, []int64{1}, true, priv1)
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{editValidatorMsg}, []int64{0}, []int64{2}, true, priv1)
validator = checkValidator(t, mApp, keeper, addr1, true)
require.Equal(t, description, validator.Description)

// delegate
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin})
delegateMsg := NewMsgDelegate(addr2, addr1, bondCoin)

mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{0}, true, priv2)
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{1}, true, priv2)
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)})
checkDelegation(t, mApp, keeper, addr2, addr1, true, sdk.NewRat(10))

// begin unbonding
beginUnbondingMsg := NewMsgBeginUnbonding(addr2, addr1, sdk.NewRat(10))
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{1}, true, priv2)
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{2}, true, priv2)

// delegation should exist anymore
checkDelegation(t, mApp, keeper, addr2, addr1, false, sdk.Rat{})
Expand Down
13 changes: 12 additions & 1 deletion x/stake/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,17 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command {
Website: viper.GetString(FlagWebsite),
Details: viper.GetString(FlagDetails),
}
msg := stake.NewMsgCreateValidator(validatorAddr, pk, amount, description)

var msg sdk.Msg
if viper.GetString(FlagAddressDelegator) != "" {
delegatorAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressDelegator))
if err != nil {
return err
}
msg = stake.NewMsgCreateValidatorOnBehalfOf(delegatorAddr, validatorAddr, pk, amount, description)
} else {
msg = stake.NewMsgCreateValidator(validatorAddr, pk, amount, description)
}

// build and sign the transaction, then broadcast to Tendermint
err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
Expand All @@ -65,6 +75,7 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command {
cmd.Flags().AddFlagSet(fsAmount)
cmd.Flags().AddFlagSet(fsDescription)
cmd.Flags().AddFlagSet(fsValidator)
cmd.Flags().AddFlagSet(fsDelegator)
return cmd
}

Expand Down
4 changes: 2 additions & 2 deletions x/stake/client/rest/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func registerTxRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, k
type msgDelegationsInput struct {
DelegatorAddr string `json:"delegator_addr"` // in bech32
ValidatorAddr string `json:"validator_addr"` // in bech32
Bond sdk.Coin `json:"bond"`
Delegation sdk.Coin `json:"delegation"`
}
type msgBeginRedelegateInput struct {
DelegatorAddr string `json:"delegator_addr"` // in bech32
Expand Down Expand Up @@ -119,7 +119,7 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte
messages[i] = stake.MsgDelegate{
DelegatorAddr: delegatorAddr,
ValidatorAddr: validatorAddr,
Bond: msg.Bond,
Delegation: msg.Delegation,
}
i++
}
Expand Down
8 changes: 4 additions & 4 deletions x/stake/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k
if found {
return ErrValidatorPubKeyExists(k.Codespace()).Result()
}
if msg.SelfDelegation.Denom != k.GetParams(ctx).BondDenom {
if msg.Delegation.Denom != k.GetParams(ctx).BondDenom {
return ErrBadDenom(k.Codespace()).Result()
}

Expand All @@ -81,7 +81,7 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k

// move coins from the msg.Address account to a (self-delegation) delegator account
// the validator account and global shares are updated within here
_, err := k.Delegate(ctx, msg.ValidatorAddr, msg.SelfDelegation, validator)
_, err := k.Delegate(ctx, msg.DelegatorAddr, msg.Delegation, validator)
if err != nil {
return err.Result()
}
Expand Down Expand Up @@ -130,13 +130,13 @@ func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper)
if !found {
return ErrNoValidatorFound(k.Codespace()).Result()
}
if msg.Bond.Denom != k.GetParams(ctx).BondDenom {
if msg.Delegation.Denom != k.GetParams(ctx).BondDenom {
return ErrBadDenom(k.Codespace()).Result()
}
if validator.Revoked == true {
return ErrValidatorRevoked(k.Codespace()).Result()
}
_, err := k.Delegate(ctx, msg.DelegatorAddr, msg.Bond, validator)
_, err := k.Delegate(ctx, msg.DelegatorAddr, msg.Delegation, validator)
if err != nil {
return err.Result()
}
Expand Down
62 changes: 47 additions & 15 deletions x/stake/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,24 @@ import (
//______________________________________________________________________

func newTestMsgCreateValidator(address sdk.AccAddress, pubKey crypto.PubKey, amt int64) MsgCreateValidator {
return MsgCreateValidator{
Description: Description{},
ValidatorAddr: address,
PubKey: pubKey,
SelfDelegation: sdk.Coin{"steak", sdk.NewInt(amt)},
}
return types.NewMsgCreateValidator(address, pubKey, sdk.Coin{"steak", sdk.NewInt(amt)}, Description{})
}

func newTestMsgDelegate(delegatorAddr, validatorAddr sdk.AccAddress, amt int64) MsgDelegate {
return MsgDelegate{
DelegatorAddr: delegatorAddr,
ValidatorAddr: validatorAddr,
Bond: sdk.Coin{"steak", sdk.NewInt(amt)},
Delegation: sdk.Coin{"steak", sdk.NewInt(amt)},
}
}

func newTestMsgCreateValidatorOnBehalfOf(delegatorAddr, validatorAddr sdk.AccAddress, valPubKey crypto.PubKey, amt int64) MsgCreateValidator {
return MsgCreateValidator{
Description: Description{},
DelegatorAddr: delegatorAddr,
ValidatorAddr: validatorAddr,
PubKey: valPubKey,
Delegation: sdk.Coin{"steak", sdk.NewInt(amt)},
}
}

Expand Down Expand Up @@ -160,6 +165,32 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) {
assert.Equal(t, Description{}, validator.Description)
}

func TestDuplicatesMsgCreateValidatorOnBehalfOf(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)

validatorAddr := keep.Addrs[0]
delegatorAddr := keep.Addrs[1]
pk := keep.PKs[0]
msgCreateValidatorOnBehalfOf := newTestMsgCreateValidatorOnBehalfOf(delegatorAddr, validatorAddr, pk, 10)
got := handleMsgCreateValidator(ctx, msgCreateValidatorOnBehalfOf, keeper)
require.True(t, got.IsOK(), "%v", got)
validator, found := keeper.GetValidator(ctx, validatorAddr)

require.True(t, found)
require.Equal(t, sdk.Bonded, validator.Status())
require.Equal(t, validatorAddr, validator.Owner)
require.Equal(t, pk, validator.PubKey)
require.Equal(t, sdk.NewRat(10), validator.PoolShares.Bonded())
require.Equal(t, sdk.NewRat(10), validator.DelegatorShares)
require.Equal(t, Description{}, validator.Description)

// one validator cannot be created twice even from different delegator
msgCreateValidatorOnBehalfOf.DelegatorAddr = keep.Addrs[2]
msgCreateValidatorOnBehalfOf.PubKey = keep.PKs[1]
got = handleMsgCreateValidator(ctx, msgCreateValidatorOnBehalfOf, keeper)
require.False(t, got.IsOK(), "%v", got)
}

func TestIncrementsMsgDelegate(t *testing.T) {
initBond := int64(1000)
ctx, accMapper, keeper := keep.CreateTestInput(t, false, initBond)
Expand Down Expand Up @@ -329,30 +360,31 @@ func TestMultipleMsgCreateValidator(t *testing.T) {
params := setInstantUnbondPeriod(keeper, ctx)

validatorAddrs := []sdk.AccAddress{keep.Addrs[0], keep.Addrs[1], keep.Addrs[2]}
delegatorAddrs := []sdk.AccAddress{keep.Addrs[3], keep.Addrs[4], keep.Addrs[5]}

// bond them all
for i, validatorAddr := range validatorAddrs {
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[i], 10)
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
msgCreateValidatorOnBehalfOf := newTestMsgCreateValidatorOnBehalfOf(delegatorAddrs[i], validatorAddr, keep.PKs[i], 10)
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
validators := keeper.GetValidators(ctx, 100)
require.Equal(t, (i + 1), len(validators))
val := validators[i]
balanceExpd := sdk.NewInt(initBond - 10)
balanceGot := accMapper.GetAccount(ctx, val.Owner).GetCoins().AmountOf(params.BondDenom)
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, 10, int(val.DelegatorShares.RoundInt64()), "expected %d shares, got %d", 10, val.DelegatorShares)
require.Equal(t, balanceExpd, balanceGot, "expected account to have %d, got %d", balanceExpd, balanceGot)
}

// unbond them all
// unbond them all by revoking delegation
for i, validatorAddr := range validatorAddrs {
validatorPre, found := keeper.GetValidator(ctx, validatorAddr)
_, found := keeper.GetValidator(ctx, validatorAddr)
require.True(t, found)
msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewRat(10)) // self-delegation
msgCompleteUnbonding := NewMsgCompleteUnbonding(validatorAddr, validatorAddr)
msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddrs[i], validatorAddr, sdk.NewRat(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)
Expand All @@ -367,7 +399,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) {
require.False(t, found)

expBalance := sdk.NewInt(initBond)
gotBalance := accMapper.GetAccount(ctx, validatorPre.Owner).GetCoins().AmountOf(params.BondDenom)
gotBalance := accMapper.GetAccount(ctx, delegatorAddrs[i]).GetCoins().AmountOf(params.BondDenom)
require.Equal(t, expBalance, gotBalance, "expected account to have %d, got %d", expBalance, gotBalance)
}
}
Expand Down
15 changes: 8 additions & 7 deletions x/stake/stake.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,14 @@ var (
DefaultGenesisState = types.DefaultGenesisState
RegisterWire = types.RegisterWire

NewMsgCreateValidator = types.NewMsgCreateValidator
NewMsgEditValidator = types.NewMsgEditValidator
NewMsgDelegate = types.NewMsgDelegate
NewMsgBeginUnbonding = types.NewMsgBeginUnbonding
NewMsgCompleteUnbonding = types.NewMsgCompleteUnbonding
NewMsgBeginRedelegate = types.NewMsgBeginRedelegate
NewMsgCompleteRedelegate = types.NewMsgCompleteRedelegate
NewMsgCreateValidator = types.NewMsgCreateValidator
NewMsgCreateValidatorOnBehalfOf = types.NewMsgCreateValidatorOnBehalfOf
NewMsgEditValidator = types.NewMsgEditValidator
NewMsgDelegate = types.NewMsgDelegate
NewMsgBeginUnbonding = types.NewMsgBeginUnbonding
NewMsgCompleteUnbonding = types.NewMsgCompleteUnbonding
NewMsgBeginRedelegate = types.NewMsgBeginRedelegate
NewMsgCompleteRedelegate = types.NewMsgCompleteRedelegate
)

const (
Expand Down
Loading

0 comments on commit b195c55

Please sign in to comment.