Skip to content

Commit

Permalink
Validator Rebalancing (#276)
Browse files Browse the repository at this point in the history
Co-authored-by: Aidan Salzmann <[email protected]>
  • Loading branch information
shellvish and asalzmann authored Oct 20, 2022
1 parent c757364 commit 725b991
Show file tree
Hide file tree
Showing 23 changed files with 1,887 additions and 971 deletions.
1,617 changes: 728 additions & 889 deletions docs/static/openapi.yml

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions proto/stakeibc/callbacks.proto
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,17 @@ message UndelegateCallback {
message RedemptionCallback {
string hostZoneId = 1;
repeated uint64 epochUnbondingRecordIds = 2;
}

// ---------------------- Validator Rebalance Callbacks ---------------------- //

message Rebalancing {
string srcValidator = 1;
string dstValidator = 2;
uint64 amt = 3;
}

message RebalanceCallback {
string hostZoneId = 1;
repeated Rebalancing rebalancings = 2;
}
4 changes: 2 additions & 2 deletions scripts-local/init_gaia.sh
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ mkdir $GAIA_HOME/config/gentx/
echo $GAIA_VAL_MNEMONIC_2 | $GAIA_CMD_2 keys add $GAIA_VAL_ACCT_2 --recover --keyring-backend=test >> $KEYS_LOGS 2>&1 &
$GAIA_CMD_2 add-genesis-account $GAIA_VAL_2_ADDR 500000000000000uatom
$GAIA_CMD add-genesis-account $GAIA_VAL_2_ADDR 500000000000000uatom
$GAIA_CMD_2 gentx $GAIA_VAL_ACCT_2 5000000000uatom --chain-id $GAIA_CHAIN --output-document=$GAIA_HOME/config/gentx/gval2.json
$GAIA_CMD_2 gentx $GAIA_VAL_ACCT_2 5000000000uatom --chain-id $GAIA_CHAIN --output-document=$GAIA_HOME/config/gentx/gval2.json 2> /dev/null

# ============================== SETUP CHAIN 3 ======================================
# echo $GAIA_VAL_MNEMONIC_3 | $GAIA_CMD_3 keys add $GAIA_VAL_ACCT_3 --recover --keyring-backend=test >> $KEYS_LOGS 2>&1 &
Expand Down Expand Up @@ -112,7 +112,7 @@ rev_addr=$($GAIA_CMD keys show $GAIA_REV_ACCT -a) > /dev/null
$GAIA_CMD collect-gentxs 2> /dev/null

## add the message types ICA should allow to the host chain
ALLOW_MESSAGES='\"/cosmos.bank.v1beta1.MsgSend\", \"/cosmos.bank.v1beta1.MsgMultiSend\", \"/cosmos.staking.v1beta1.MsgDelegate\", \"/cosmos.staking.v1beta1.MsgUndelegate\", \"/cosmos.staking.v1beta1.MsgRedeemTokensforShares\", \"/cosmos.staking.v1beta1.MsgTokenizeShares\", \"/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward\", \"/cosmos.distribution.v1beta1.MsgSetWithdrawAddress\", \"/ibc.applications.transfer.v1.MsgTransfer\"'
ALLOW_MESSAGES='\"/cosmos.bank.v1beta1.MsgSend\", \"/cosmos.bank.v1beta1.MsgMultiSend\", \"/cosmos.staking.v1beta1.MsgDelegate\", \"/cosmos.staking.v1beta1.MsgUndelegate\", \"/cosmos.staking.v1beta1.MsgBeginRedelegate\", \"/cosmos.staking.v1beta1.MsgRedeemTokensforShares\", \"/cosmos.staking.v1beta1.MsgTokenizeShares\", \"/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward\", \"/cosmos.distribution.v1beta1.MsgSetWithdrawAddress\", \"/ibc.applications.transfer.v1.MsgTransfer\"'
sed -i -E "s|\"allow_messages\": \[\]|\"allow_messages\": \[${ALLOW_MESSAGES}\]|g" "${STATE}/${GAIA_NODE_NAME}/config/genesis.json"

cp $GAIA_HOME/config/genesis.json $GAIA_HOME_2/config/genesis.json
Expand Down
2 changes: 1 addition & 1 deletion scripts-local/init_juno.sh
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ rev_addr=$($JUNO_CMD keys show $JUNO_REV_ACCT --keyring-backend test -a) > /dev/
$JUNO_CMD collect-gentxs 2> /dev/null

## add the message types ICA should allow to the host chain
ALLOW_MESSAGES='\"/cosmos.bank.v1beta1.MsgSend\", \"/cosmos.bank.v1beta1.MsgMultiSend\", \"/cosmos.staking.v1beta1.MsgDelegate\", \"/cosmos.staking.v1beta1.MsgUndelegate\", \"/cosmos.staking.v1beta1.MsgRedeemTokensforShares\", \"/cosmos.staking.v1beta1.MsgTokenizeShares\", \"/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward\", \"/cosmos.distribution.v1beta1.MsgSetWithdrawAddress\", \"/ibc.applications.transfer.v1.MsgTransfer\"'
ALLOW_MESSAGES='\"/cosmos.bank.v1beta1.MsgSend\", \"/cosmos.bank.v1beta1.MsgMultiSend\", \"/cosmos.staking.v1beta1.MsgDelegate\", \"/cosmos.staking.v1beta1.MsgUndelegate\", \"/cosmos.staking.v1beta1.MsgBeginRedelegate\", \"/cosmos.staking.v1beta1.MsgRedeemTokensforShares\", \"/cosmos.staking.v1beta1.MsgTokenizeShares\", \"/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward\", \"/cosmos.distribution.v1beta1.MsgSetWithdrawAddress\", \"/ibc.applications.transfer.v1.MsgTransfer\"'
sed -i -E "s|\"allow_messages\": \[\]|\"allow_messages\": \[${ALLOW_MESSAGES}\]|g" "${STATE}/${JUNO_NODE_NAME}/config/genesis.json"

# Update ports so they don't conflict with the stride chain
Expand Down
2 changes: 1 addition & 1 deletion scripts-local/init_osmo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ rev_addr=$($OSMO_CMD keys show $OSMO_REV_ACCT --keyring-backend test -a) > /dev/
$OSMO_CMD collect-gentxs 2> /dev/null

## add the message types ICA should allow to the host chain
ALLOW_MESSAGES='\"/cosmos.bank.v1beta1.MsgSend\", \"/cosmos.bank.v1beta1.MsgMultiSend\", \"/cosmos.staking.v1beta1.MsgDelegate\", \"/cosmos.staking.v1beta1.MsgUndelegate\", \"/cosmos.staking.v1beta1.MsgRedeemTokensforShares\", \"/cosmos.staking.v1beta1.MsgTokenizeShares\", \"/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward\", \"/cosmos.distribution.v1beta1.MsgSetWithdrawAddress\", \"/ibc.applications.transfer.v1.MsgTransfer\"'
ALLOW_MESSAGES='\"/cosmos.bank.v1beta1.MsgSend\", \"/cosmos.bank.v1beta1.MsgMultiSend\", \"/cosmos.staking.v1beta1.MsgDelegate\", \"/cosmos.staking.v1beta1.MsgUndelegate\", \"/cosmos.staking.v1beta1.MsgBeginRedelegate\", \"/cosmos.staking.v1beta1.MsgRedeemTokensforShares\", \"/cosmos.staking.v1beta1.MsgTokenizeShares\", \"/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward\", \"/cosmos.distribution.v1beta1.MsgSetWithdrawAddress\", \"/ibc.applications.transfer.v1.MsgTransfer\"'
sed -i -E "s|\"allow_messages\": \[\]|\"allow_messages\": \[${ALLOW_MESSAGES}\]|g" "${STATE}/${OSMO_NODE_NAME}/config/genesis.json"

# Update ports so they don't conflict with the stride chain
Expand Down
1 change: 1 addition & 0 deletions scripts-local/start_network.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
source $SCRIPT_DIR/vars.sh

mkdir -p $SCRIPT_DIR/logs
mkdir -p $SCRIPT_DIR/logs/rly

CACHE="${1:-false}"

Expand Down
8 changes: 4 additions & 4 deletions scripts-local/vars.sh
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,10 @@ GAIA_LOGS=$SCRIPT_DIR/logs/gaia.log
GAIA_LOGS_2=$SCRIPT_DIR/logs/gaia2.log
GAIA_LOGS_3=$SCRIPT_DIR/logs/gaia3.log
HERMES_LOGS=$SCRIPT_DIR/logs/hermes.log
RLY_GAIA_LOGS=$SCRIPT_DIR/logs/rly_gaia.log
RLY_OSMO_LOGS=$SCRIPT_DIR/logs/rly_osmo.log
RLY_JUNO_LOGS=$SCRIPT_DIR/logs/rly_juno.log
ICQ_LOGS=$SCRIPT_DIR/logs/icq.log
RLY_GAIA_LOGS=$SCRIPT_DIR/logs/rly/rly_gaia.log
RLY_OSMO_LOGS=$SCRIPT_DIR/logs/rly/rly_osmo.log
RLY_JUNO_LOGS=$SCRIPT_DIR/logs/rly/rly_juno.log
ICQ_LOGS=$SCRIPT_DIR/logs/rly/icq.log
JUNO_LOGS=$SCRIPT_DIR/logs/juno.log
OSMO_LOGS=$SCRIPT_DIR/logs/osmo.log
TX_LOGS=$SCRIPT_DIR/logs/tx.log
Expand Down
1 change: 1 addition & 0 deletions scripts/config/ica.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"/cosmos.bank.v1beta1.MsgMultiSend",
"/cosmos.staking.v1beta1.MsgDelegate",
"/cosmos.staking.v1beta1.MsgUndelegate",
"/cosmos.staking.v1beta1.MsgBeginRedelegate",
"/cosmos.staking.v1beta1.MsgRedeemTokensforShares",
"/cosmos.staking.v1beta1.MsgTokenizeShares",
"/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward",
Expand Down
2 changes: 1 addition & 1 deletion x/epochs/types/query.pb.gw.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion x/icacallbacks/types/query.pb.gw.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion x/interchainquery/types/messages.pb.gw.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion x/mint/types/query.pb.gw.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion x/records/types/query.pb.gw.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion x/stakeibc/client/cli/tx_rebalance_validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ var _ = strconv.Itoa(0)

func CmdRebalanceValidators() *cobra.Command {
cmd := &cobra.Command{
Use: "rebalance-validators [host-zone]",
Use: "rebalance-validators [host-zone] [num-to-rebalance]",
Short: "Broadcast message rebalanceValidators",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) (err error) {
Expand Down
4 changes: 3 additions & 1 deletion x/stakeibc/keeper/icacallbacks.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const (
UNDELEGATE = "undelegate"
REINVEST = "reinvest"
REDEMPTION = "redemption"
REBALANCE = "rebalance"
)

// ICACallbacks wrapper struct for stakeibc keeper
Expand Down Expand Up @@ -49,6 +50,7 @@ func (c ICACallbacks) RegisterICACallbacks() icacallbackstypes.ICACallbackHandle
AddICACallback(CLAIM, ICACallback(ClaimCallback)).
AddICACallback(UNDELEGATE, ICACallback(UndelegateCallback)).
AddICACallback(REINVEST, ICACallback(ReinvestCallback)).
AddICACallback(REDEMPTION, ICACallback(RedemptionCallback))
AddICACallback(REDEMPTION, ICACallback(RedemptionCallback)).
AddICACallback(REBALANCE, ICACallback(RebalanceCallback))
return a.(ICACallbacks)
}
93 changes: 93 additions & 0 deletions x/stakeibc/keeper/icacallbacks_rebalance.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package keeper

import (
"fmt"

"github.com/Stride-Labs/stride/x/icacallbacks"
icacallbackstypes "github.com/Stride-Labs/stride/x/icacallbacks/types"
"github.com/Stride-Labs/stride/x/stakeibc/types"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types"
"github.com/golang/protobuf/proto" //nolint:staticcheck
)

func (k Keeper) MarshalRebalanceCallbackArgs(ctx sdk.Context, rebalanceCallback types.RebalanceCallback) ([]byte, error) {
out, err := proto.Marshal(&rebalanceCallback)
if err != nil {
k.Logger(ctx).Error(fmt.Sprintf("MarshalRebalanceCallbackArgs %v", err.Error()))
return nil, err
}
return out, nil
}

func (k Keeper) UnmarshalRebalanceCallbackArgs(ctx sdk.Context, rebalanceCallback []byte) (*types.RebalanceCallback, error) {
unmarshalledRebalanceCallback := types.RebalanceCallback{}
if err := proto.Unmarshal(rebalanceCallback, &unmarshalledRebalanceCallback); err != nil {
k.Logger(ctx).Error(fmt.Sprintf("UnmarshalRebalanceCallbackArgs %v", err.Error()))
return nil, err
}
return &unmarshalledRebalanceCallback, nil
}

func RebalanceCallback(k Keeper, ctx sdk.Context, packet channeltypes.Packet, ack *channeltypes.Acknowledgement, args []byte) error {
k.Logger(ctx).Info("RebalanceCallback executing", "packet", packet)
if ack == nil {
// timeout
k.Logger(ctx).Error(fmt.Sprintf("RebalanceCallback timeout, ack is nil, packet %v", packet))
return nil
}

txMsgData, err := icacallbacks.GetTxMsgData(ctx, *ack, k.Logger(ctx))
if err != nil {
k.Logger(ctx).Error(fmt.Sprintf("failed to fetch txMsgData, packet %v", packet))
return sdkerrors.Wrap(icacallbackstypes.ErrTxMsgData, err.Error())
}

if len(txMsgData.Data) == 0 {
// failed transaction
k.Logger(ctx).Error(fmt.Sprintf("RebalanceCallback tx failed, ack is empty (ack error), packet %v", packet))
return nil
}

// deserialize the args
rebalanceCallback, err := k.UnmarshalRebalanceCallbackArgs(ctx, args)
if err != nil {
errMsg := fmt.Sprintf("Unable to unmarshal rebalance callback args | %s", err.Error())
k.Logger(ctx).Error(errMsg)
return sdkerrors.Wrapf(types.ErrUnmarshalFailure, errMsg)
}
k.Logger(ctx).Info(fmt.Sprintf("RebalanceCallback %v", rebalanceCallback))
hostZone := rebalanceCallback.GetHostZoneId()
zone, found := k.GetHostZone(ctx, hostZone)
if !found {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "host zone not found %s", hostZone)
}

// update the host zone
rebalancings := rebalanceCallback.GetRebalancings()
// assemble a map from validatorAddress -> validator
valAddrMap := make(map[string]*types.Validator)
for _, val := range zone.GetValidators() {
valAddrMap[val.GetAddress()] = val
}
for _, rebalancing := range rebalancings {
srcValidator := rebalancing.GetSrcValidator()
dstValidator := rebalancing.GetDstValidator()
amt := rebalancing.GetAmt()
if _, valFound := valAddrMap[srcValidator]; valFound {
valAddrMap[srcValidator].DelegationAmt -= amt
} else {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "validator not found %s", srcValidator)
}
if _, valFound := valAddrMap[dstValidator]; valFound {
valAddrMap[dstValidator].DelegationAmt += amt
} else {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "validator not found %s", dstValidator)
}
}
k.SetHostZone(ctx, zone)

return nil
}
Loading

0 comments on commit 725b991

Please sign in to comment.