-
Notifications
You must be signed in to change notification settings - Fork 579
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore: replace error string in transfer acks with const (backport #818) #993
Merged
crodriguezvega
merged 5 commits into
release/v2.1.x
from
mergify/bp/release/v2.1.x/pr-818
Mar 1, 2022
Merged
Changes from 1 commit
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
2e51bab
chore: replace error string in transfer acks with const (#818)
damiannolan d333aa7
fix merge conflicts
3d289a7
fix changelog
1aafe51
Merge branch 'release/v2.1.x' into mergify/bp/release/v2.1.x/pr-818
crodriguezvega cc226e0
Merge branch 'release/v2.1.x' into mergify/bp/release/v2.1.x/pr-818
crodriguezvega File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package types | ||
|
||
import ( | ||
"fmt" | ||
|
||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
|
||
channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" | ||
) | ||
|
||
const ( | ||
// ackErrorString defines a string constant included in error acknowledgements | ||
// NOTE: Changing this const is state machine breaking as acknowledgements are written into state | ||
ackErrorString = "error handling packet on host chain: see events for details" | ||
) | ||
|
||
// NewErrorAcknowledgement returns a deterministic error string which may be used in | ||
// the packet acknowledgement. | ||
func NewErrorAcknowledgement(err error) channeltypes.Acknowledgement { | ||
// the ABCI code is included in the abcitypes.ResponseDeliverTx hash | ||
// constructed in Tendermint and is therefore determinstic | ||
_, code, _ := sdkerrors.ABCIInfo(err, false) // discard non-deterministic codespace and log values | ||
|
||
errorString := fmt.Sprintf("ABCI code: %d: %s", code, ackErrorString) | ||
|
||
return channeltypes.NewErrorAcknowledgement(errorString) | ||
} |
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,280 @@ | ||
package transfer | ||
|
||
import ( | ||
"fmt" | ||
"math" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" | ||
|
||
"github.com/cosmos/ibc-go/v3/modules/apps/transfer/keeper" | ||
"github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" | ||
channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" | ||
porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" | ||
host "github.com/cosmos/ibc-go/v3/modules/core/24-host" | ||
ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" | ||
) | ||
|
||
// IBCModule implements the ICS26 interface for transfer given the transfer keeper. | ||
type IBCModule struct { | ||
keeper keeper.Keeper | ||
} | ||
|
||
// NewIBCModule creates a new IBCModule given the keeper | ||
func NewIBCModule(k keeper.Keeper) IBCModule { | ||
return IBCModule{ | ||
keeper: k, | ||
} | ||
} | ||
|
||
// ValidateTransferChannelParams does validation of a newly created transfer channel. A transfer | ||
// channel must be UNORDERED, use the correct port (by default 'transfer'), and use the current | ||
// supported version. Only 2^32 channels are allowed to be created. | ||
func ValidateTransferChannelParams( | ||
ctx sdk.Context, | ||
keeper keeper.Keeper, | ||
order channeltypes.Order, | ||
portID string, | ||
channelID string, | ||
) error { | ||
// NOTE: for escrow address security only 2^32 channels are allowed to be created | ||
// Issue: https://github.com/cosmos/cosmos-sdk/issues/7737 | ||
channelSequence, err := channeltypes.ParseChannelSequence(channelID) | ||
if err != nil { | ||
return err | ||
} | ||
if channelSequence > uint64(math.MaxUint32) { | ||
return sdkerrors.Wrapf(types.ErrMaxTransferChannels, "channel sequence %d is greater than max allowed transfer channels %d", channelSequence, uint64(math.MaxUint32)) | ||
} | ||
if order != channeltypes.UNORDERED { | ||
return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s ", channeltypes.UNORDERED, order) | ||
} | ||
|
||
// Require portID is the portID transfer module is bound to | ||
boundPort := keeper.GetPort(ctx) | ||
if boundPort != portID { | ||
return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "invalid port: %s, expected %s", portID, boundPort) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// OnChanOpenInit implements the IBCModule interface | ||
func (im IBCModule) OnChanOpenInit( | ||
ctx sdk.Context, | ||
order channeltypes.Order, | ||
connectionHops []string, | ||
portID string, | ||
channelID string, | ||
chanCap *capabilitytypes.Capability, | ||
counterparty channeltypes.Counterparty, | ||
version string, | ||
) error { | ||
if err := ValidateTransferChannelParams(ctx, im.keeper, order, portID, channelID); err != nil { | ||
return err | ||
} | ||
|
||
if version != types.Version { | ||
return sdkerrors.Wrapf(types.ErrInvalidVersion, "got %s, expected %s", version, types.Version) | ||
} | ||
|
||
// Claim channel capability passed back by IBC module | ||
if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// OnChanOpenTry implements the IBCModule interface. | ||
func (im IBCModule) OnChanOpenTry( | ||
ctx sdk.Context, | ||
order channeltypes.Order, | ||
connectionHops []string, | ||
portID, | ||
channelID string, | ||
chanCap *capabilitytypes.Capability, | ||
counterparty channeltypes.Counterparty, | ||
counterpartyVersion string, | ||
) (string, error) { | ||
if err := ValidateTransferChannelParams(ctx, im.keeper, order, portID, channelID); err != nil { | ||
return "", err | ||
} | ||
|
||
if counterpartyVersion != types.Version { | ||
return "", sdkerrors.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: got: %s, expected %s", counterpartyVersion, types.Version) | ||
} | ||
|
||
// Module may have already claimed capability in OnChanOpenInit in the case of crossing hellos | ||
// (ie chainA and chainB both call ChanOpenInit before one of them calls ChanOpenTry) | ||
// If module can already authenticate the capability then module already owns it so we don't need to claim | ||
// Otherwise, module does not have channel capability and we must claim it from IBC | ||
if !im.keeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) { | ||
// Only claim channel capability passed back by IBC module if we do not already own it | ||
if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { | ||
return "", err | ||
} | ||
} | ||
|
||
return types.Version, nil | ||
} | ||
|
||
// OnChanOpenAck implements the IBCModule interface | ||
func (im IBCModule) OnChanOpenAck( | ||
ctx sdk.Context, | ||
portID, | ||
channelID string, | ||
counterpartyVersion string, | ||
) error { | ||
if counterpartyVersion != types.Version { | ||
return sdkerrors.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: %s, expected %s", counterpartyVersion, types.Version) | ||
} | ||
return nil | ||
} | ||
|
||
// OnChanOpenConfirm implements the IBCModule interface | ||
func (im IBCModule) OnChanOpenConfirm( | ||
ctx sdk.Context, | ||
portID, | ||
channelID string, | ||
) error { | ||
return nil | ||
} | ||
|
||
// OnChanCloseInit implements the IBCModule interface | ||
func (im IBCModule) OnChanCloseInit( | ||
ctx sdk.Context, | ||
portID, | ||
channelID string, | ||
) error { | ||
// Disallow user-initiated channel closing for transfer channels | ||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "user cannot close channel") | ||
} | ||
|
||
// OnChanCloseConfirm implements the IBCModule interface | ||
func (im IBCModule) OnChanCloseConfirm( | ||
ctx sdk.Context, | ||
portID, | ||
channelID string, | ||
) error { | ||
return nil | ||
} | ||
|
||
// OnRecvPacket implements the IBCModule interface. A successful acknowledgement | ||
// is returned if the packet data is succesfully decoded and the receive application | ||
// logic returns without error. | ||
func (im IBCModule) OnRecvPacket( | ||
ctx sdk.Context, | ||
packet channeltypes.Packet, | ||
relayer sdk.AccAddress, | ||
) ibcexported.Acknowledgement { | ||
ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) | ||
|
||
var data types.FungibleTokenPacketData | ||
if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { | ||
ack = channeltypes.NewErrorAcknowledgement("cannot unmarshal ICS-20 transfer packet data") | ||
} | ||
|
||
// only attempt the application logic if the packet data | ||
// was successfully decoded | ||
if ack.Success() { | ||
err := im.keeper.OnRecvPacket(ctx, packet, data) | ||
if err != nil { | ||
ack = types.NewErrorAcknowledgement(err) | ||
} | ||
} | ||
|
||
ctx.EventManager().EmitEvent( | ||
sdk.NewEvent( | ||
types.EventTypePacket, | ||
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), | ||
sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), | ||
sdk.NewAttribute(types.AttributeKeyDenom, data.Denom), | ||
sdk.NewAttribute(types.AttributeKeyAmount, data.Amount), | ||
sdk.NewAttribute(types.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack.Success())), | ||
), | ||
) | ||
|
||
// NOTE: acknowledgement will be written synchronously during IBC handler execution. | ||
return ack | ||
} | ||
|
||
// OnAcknowledgementPacket implements the IBCModule interface | ||
func (im IBCModule) OnAcknowledgementPacket( | ||
ctx sdk.Context, | ||
packet channeltypes.Packet, | ||
acknowledgement []byte, | ||
relayer sdk.AccAddress, | ||
) error { | ||
var ack channeltypes.Acknowledgement | ||
if err := types.ModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { | ||
return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet acknowledgement: %v", err) | ||
} | ||
var data types.FungibleTokenPacketData | ||
if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { | ||
return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet data: %s", err.Error()) | ||
} | ||
|
||
if err := im.keeper.OnAcknowledgementPacket(ctx, packet, data, ack); err != nil { | ||
return err | ||
} | ||
|
||
ctx.EventManager().EmitEvent( | ||
sdk.NewEvent( | ||
types.EventTypePacket, | ||
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), | ||
sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), | ||
sdk.NewAttribute(types.AttributeKeyDenom, data.Denom), | ||
sdk.NewAttribute(types.AttributeKeyAmount, data.Amount), | ||
sdk.NewAttribute(types.AttributeKeyAck, ack.String()), | ||
), | ||
) | ||
|
||
switch resp := ack.Response.(type) { | ||
case *channeltypes.Acknowledgement_Result: | ||
ctx.EventManager().EmitEvent( | ||
sdk.NewEvent( | ||
types.EventTypePacket, | ||
sdk.NewAttribute(types.AttributeKeyAckSuccess, string(resp.Result)), | ||
), | ||
) | ||
case *channeltypes.Acknowledgement_Error: | ||
ctx.EventManager().EmitEvent( | ||
sdk.NewEvent( | ||
types.EventTypePacket, | ||
sdk.NewAttribute(types.AttributeKeyAckError, resp.Error), | ||
), | ||
) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// OnTimeoutPacket implements the IBCModule interface | ||
func (im IBCModule) OnTimeoutPacket( | ||
ctx sdk.Context, | ||
packet channeltypes.Packet, | ||
relayer sdk.AccAddress, | ||
) error { | ||
var data types.FungibleTokenPacketData | ||
if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { | ||
return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet data: %s", err.Error()) | ||
} | ||
// refund tokens | ||
if err := im.keeper.OnTimeoutPacket(ctx, packet, data); err != nil { | ||
return err | ||
} | ||
|
||
ctx.EventManager().EmitEvent( | ||
sdk.NewEvent( | ||
types.EventTypeTimeout, | ||
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), | ||
sdk.NewAttribute(types.AttributeKeyRefundReceiver, data.Sender), | ||
sdk.NewAttribute(types.AttributeKeyRefundDenom, data.Denom), | ||
sdk.NewAttribute(types.AttributeKeyRefundAmount, data.Amount), | ||
), | ||
) | ||
|
||
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,27 @@ | ||
package types | ||
|
||
import ( | ||
"fmt" | ||
|
||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
|
||
channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" | ||
) | ||
|
||
const ( | ||
// ackErrorString defines a string constant included in error acknowledgements | ||
// NOTE: Changing this const is state machine breaking as acknowledgements are written into state | ||
ackErrorString = "error handling packet on destination chain: see events for details" | ||
) | ||
|
||
// NewErrorAcknowledgement returns a deterministic error string which may be used in | ||
// the packet acknowledgement. | ||
func NewErrorAcknowledgement(err error) channeltypes.Acknowledgement { | ||
// the ABCI code is included in the abcitypes.ResponseDeliverTx hash | ||
// constructed in Tendermint and is therefore deterministic | ||
_, code, _ := sdkerrors.ABCIInfo(err, false) // discard non-determinstic codespace and log values | ||
|
||
errorString := fmt.Sprintf("ABCI code: %d: %s", code, ackErrorString) | ||
|
||
return channeltypes.NewErrorAcknowledgement(errorString) | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this file in the diffs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
merge conflicts most likely