-
Notifications
You must be signed in to change notification settings - Fork 204
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add rounding calibration function (#936)
Closes: #XXX ## Context and purpose of the change ## Brief Changelog ## Author's Checklist I have... - [ ] Run and PASSED locally all GAIA integration tests - [ ] If the change is contentful, I either: - [ ] Added a new unit test OR - [ ] Added test cases to existing unit tests - [ ] OR this change is a trivial rework / code cleanup without any test coverage If skipped any of the tests above, explain. ## Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] manually tested (if applicable) - [ ] confirmed the author wrote unit tests for new logic - [ ] reviewed documentation exists and is accurate ## Documentation and Release Note - [ ] Does this pull request introduce a new feature or user-facing behavior changes? - [ ] Is a relevant changelog entry added to the `Unreleased` section in `CHANGELOG.md`? - [ ] This pull request updates existing proto field values (and require a backend and frontend migration)? - [ ] Does this pull request change existing proto field names (and require a frontend migration)? How is the feature or change documented? - [ ] not applicable - [ ] jira ticket `XXX` - [ ] specification (`x/<module>/spec/`) - [ ] README.md - [ ] not documented
- Loading branch information
Showing
11 changed files
with
837 additions
and
91 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package cli | ||
|
||
import ( | ||
"github.com/cosmos/cosmos-sdk/client" | ||
"github.com/cosmos/cosmos-sdk/client/flags" | ||
"github.com/cosmos/cosmos-sdk/client/tx" | ||
"github.com/spf13/cobra" | ||
|
||
"github.com/Stride-Labs/stride/v14/x/stakeibc/types" | ||
) | ||
|
||
func CmdCalibrateDelegation() *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "calibrate-delegation [chainid] [valoper]", | ||
Short: "Broadcast message calibrate-delegation", | ||
Args: cobra.ExactArgs(2), | ||
RunE: func(cmd *cobra.Command, args []string) (err error) { | ||
argChainId := args[0] | ||
argValoper := args[1] | ||
|
||
clientCtx, err := client.GetClientTxContext(cmd) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
msg := types.NewMsgCalibrateDelegation( | ||
clientCtx.GetFromAddress().String(), | ||
argChainId, | ||
argValoper, | ||
) | ||
if err := msg.ValidateBasic(); err != nil { | ||
return err | ||
} | ||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) | ||
}, | ||
} | ||
|
||
flags.AddTxFlagsToCmd(cmd) | ||
|
||
return cmd | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
x/stakeibc/keeper/icqcallbacks_callibrate_delegation.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package keeper | ||
|
||
import ( | ||
errorsmod "cosmossdk.io/errors" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" | ||
"github.com/cosmos/gogoproto/proto" | ||
|
||
"github.com/Stride-Labs/stride/v14/utils" | ||
icqtypes "github.com/Stride-Labs/stride/v14/x/interchainquery/types" | ||
"github.com/Stride-Labs/stride/v14/x/stakeibc/types" | ||
) | ||
|
||
// DelegatorSharesCallback is a callback handler for UpdateValidatorSharesExchRate queries. | ||
// | ||
// In an attempt to get the ICA's delegation amount on a given validator, we have to query: | ||
// 1. the validator's internal shares to tokens rate | ||
// 2. the Delegation ICA's delegated shares | ||
// And apply the following equation: | ||
// numTokens = numShares * sharesToTokensRate | ||
// | ||
// This is the callback from query #2 | ||
// | ||
// Note: for now, to get proofs in your ICQs, you need to query the entire store on the host zone! e.g. "store/bank/key" | ||
func CalibrateDelegationCallback(k Keeper, ctx sdk.Context, args []byte, query icqtypes.Query) error { | ||
k.Logger(ctx).Info(utils.LogICQCallbackWithHostZone(query.ChainId, ICQCallbackID_Calibrate, | ||
"Starting delegator shares callback, QueryId: %vs, QueryType: %s, Connection: %s", query.Id, query.QueryType, query.ConnectionId)) | ||
|
||
// Confirm host exists | ||
chainId := query.ChainId | ||
hostZone, found := k.GetHostZone(ctx, chainId) | ||
if !found { | ||
return errorsmod.Wrapf(types.ErrHostZoneNotFound, "no registered zone for queried chain ID (%s)", chainId) | ||
} | ||
|
||
// Unmarshal the query response which returns a delegation object for the delegator/validator pair | ||
queriedDelegation := stakingtypes.Delegation{} | ||
err := k.cdc.Unmarshal(args, &queriedDelegation) | ||
if err != nil { | ||
return errorsmod.Wrapf(err, "unable to unmarshal delegator shares query response into Delegation type") | ||
} | ||
k.Logger(ctx).Info(utils.LogICQCallbackWithHostZone(chainId, ICQCallbackID_Calibrate, "Query response - Delegator: %s, Validator: %s, Shares: %v", | ||
queriedDelegation.DelegatorAddress, queriedDelegation.ValidatorAddress, queriedDelegation.Shares)) | ||
|
||
// Unmarshal the callback data containing the previous delegation to the validator (from the time the query was submitted) | ||
var callbackData types.DelegatorSharesQueryCallback | ||
if err := proto.Unmarshal(query.CallbackData, &callbackData); err != nil { | ||
return errorsmod.Wrapf(err, "unable to unmarshal delegator shares callback data") | ||
} | ||
|
||
// Grab the validator object from the hostZone using the address returned from the query | ||
validator, valIndex, found := GetValidatorFromAddress(hostZone.Validators, queriedDelegation.ValidatorAddress) | ||
if !found { | ||
return errorsmod.Wrapf(types.ErrValidatorNotFound, "no registered validator for address (%s)", queriedDelegation.ValidatorAddress) | ||
} | ||
|
||
// Check if the ICQ overlapped a delegation, undelegation, or detokenization ICA | ||
// that would have modfied the number of delegated tokens | ||
prevInternalDelegation := callbackData.InitialValidatorDelegation | ||
currInternalDelegation := validator.Delegation | ||
icaOverlappedIcq, err := k.CheckDelegationChangedDuringQuery(ctx, validator, prevInternalDelegation, currInternalDelegation) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// If the ICA/ICQ overlapped, submit a new query | ||
if icaOverlappedIcq { | ||
// Store the updated validator delegation amount | ||
callbackDataBz, err := proto.Marshal(&types.DelegatorSharesQueryCallback{ | ||
InitialValidatorDelegation: currInternalDelegation, | ||
}) | ||
if err != nil { | ||
return errorsmod.Wrapf(err, "unable to marshal delegator shares callback data") | ||
} | ||
query.CallbackData = callbackDataBz | ||
|
||
if err := k.InterchainQueryKeeper.RetryICQRequest(ctx, query); err != nil { | ||
return errorsmod.Wrapf(err, "unable to resubmit delegator shares query") | ||
} | ||
return nil | ||
} | ||
|
||
// If there was no ICA/ICQ overlap, update the validator to indicate that the query | ||
// is no longer in progress (which will unblock LSM liquid stakes to that validator) | ||
validator.SlashQueryInProgress = false | ||
|
||
// Calculate the number of tokens delegated (using the internal sharesToTokensRate) | ||
// note: truncateInt per https://github.com/cosmos/cosmos-sdk/blob/cb31043d35bad90c4daa923bb109f38fd092feda/x/staking/types/validator.go#L431 | ||
delegatedTokens := queriedDelegation.Shares.Mul(validator.SharesToTokensRate).TruncateInt() | ||
k.Logger(ctx).Info(utils.LogICQCallbackWithHostZone(chainId, ICQCallbackID_Calibrate, | ||
"Previous Delegation: %v, Current Delegation: %v", validator.Delegation, delegatedTokens)) | ||
|
||
// Confirm the validator has actually been slashed | ||
if delegatedTokens.Equal(validator.Delegation) { | ||
k.Logger(ctx).Info(utils.LogICQCallbackWithHostZone(chainId, ICQCallbackID_Calibrate, "Validator delegation is correct")) | ||
return nil | ||
} | ||
|
||
delegationChange := validator.Delegation.Sub(delegatedTokens) | ||
validator.Delegation = validator.Delegation.Sub(delegationChange) | ||
hostZone.TotalDelegations = hostZone.TotalDelegations.Sub(delegationChange) | ||
|
||
k.Logger(ctx).Info(utils.LogICQCallbackWithHostZone(chainId, ICQCallbackID_Calibrate, | ||
"Delegation updated to: %v", validator.Delegation)) | ||
|
||
hostZone.Validators[valIndex] = &validator | ||
k.SetHostZone(ctx, hostZone) | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package keeper | ||
|
||
import ( | ||
"context" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
|
||
"github.com/Stride-Labs/stride/v14/x/stakeibc/types" | ||
) | ||
|
||
// Submits an ICQ to get the validator's delegated shares | ||
func (k msgServer) CalibrateDelegation(goCtx context.Context, msg *types.MsgCalibrateDelegation) (*types.MsgCalibrateDelegationResponse, error) { | ||
ctx := sdk.UnwrapSDKContext(goCtx) | ||
|
||
hostZone, found := k.GetHostZone(ctx, msg.ChainId) | ||
if !found { | ||
return nil, types.ErrHostZoneNotFound | ||
} | ||
|
||
if err := k.SubmitCalibrationICQ(ctx, hostZone, msg.Valoper); err != nil { | ||
return nil, err | ||
} | ||
|
||
return &types.MsgCalibrateDelegationResponse{}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package types | ||
|
||
import ( | ||
"strings" | ||
|
||
errorsmod "cosmossdk.io/errors" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
|
||
"github.com/Stride-Labs/stride/v14/utils" | ||
) | ||
|
||
const TypeMsgCalibrateDelegation = "calibrate_delegation" | ||
|
||
var _ sdk.Msg = &MsgCalibrateDelegation{} | ||
|
||
func NewMsgCalibrateDelegation(creator string, chainid string, valoper string) *MsgCalibrateDelegation { | ||
return &MsgCalibrateDelegation{ | ||
Creator: creator, | ||
ChainId: chainid, | ||
Valoper: valoper, | ||
} | ||
} | ||
|
||
func (msg *MsgCalibrateDelegation) Route() string { | ||
return RouterKey | ||
} | ||
|
||
func (msg *MsgCalibrateDelegation) Type() string { | ||
return TypeMsgCalibrateDelegation | ||
} | ||
|
||
func (msg *MsgCalibrateDelegation) GetSigners() []sdk.AccAddress { | ||
creator, err := sdk.AccAddressFromBech32(msg.Creator) | ||
if err != nil { | ||
panic(err) | ||
} | ||
return []sdk.AccAddress{creator} | ||
} | ||
|
||
func (msg *MsgCalibrateDelegation) GetSignBytes() []byte { | ||
bz := ModuleCdc.MustMarshalJSON(msg) | ||
return sdk.MustSortJSON(bz) | ||
} | ||
|
||
func (msg *MsgCalibrateDelegation) ValidateBasic() error { | ||
_, err := sdk.AccAddressFromBech32(msg.Creator) | ||
if err != nil { | ||
return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) | ||
} | ||
if err := utils.ValidateAdminAddress(msg.Creator); err != nil { | ||
return err | ||
} | ||
|
||
if len(msg.ChainId) == 0 { | ||
return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "chainid is required") | ||
} | ||
if len(msg.Valoper) == 0 { | ||
return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "valoper is required") | ||
} | ||
if !strings.Contains(msg.Valoper, "valoper") { | ||
return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "validator operator address must contrain 'valoper'") | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.