-
Notifications
You must be signed in to change notification settings - Fork 409
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
Spike error ack #1299
Spike error ack #1299
Changes from 2 commits
03c264c
610c677
fcd0040
a59ccb8
2df007f
dbc3483
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
package wasm | ||
|
||
import ( | ||
"fmt" | ||
"math" | ||
|
||
errorsmod "cosmossdk.io/errors" | ||
|
@@ -267,23 +268,38 @@ func (i IBCHandler) OnRecvPacket( | |
return channeltypes.NewErrorAcknowledgement(errorsmod.Wrapf(err, "contract port id")) | ||
} | ||
msg := wasmvmtypes.IBCPacketReceiveMsg{Packet: newIBCPacket(packet), Relayer: relayer.String()} | ||
ack, err := i.keeper.OnRecvPacket(ctx, contractAddr, msg) | ||
|
||
em := sdk.NewEventManager() | ||
ack, err := i.keeper.OnRecvPacket(ctx.WithEventManager(em), contractAddr, msg) | ||
if err != nil { | ||
// the state gets reverted, we keep only wasm events that do not contain custom data | ||
for _, e := range em.Events() { | ||
if types.IsAcceptedEventOnRecvPacketErrorAck(e.Type) { | ||
ctx.EventManager().EmitEvent(e) | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we really want to preserve those events? I might be messing something but to me it's clearer if we discard them and add all relevent information in the error event below. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In a more complex contract-calls-contracts environment, the event trace may have revealed some infos to track the root cause of an error. But there are some costs of maintaining this in the future. |
||
// the `NewErrorAcknowledgement` redacts the error message, it is | ||
// recommended by the ibc-module devs to log the raw error as event: | ||
ctx.EventManager().EmitEvent( | ||
sdk.NewEvent( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we always emit an event on rcv or on only in the error case? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about 2 events:
While There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was also inspired by ics-20 and ics-27 . They use a single event with additional error attribute when set. |
||
types.EventTypePacketRecv, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fyi: the event name is |
||
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), | ||
sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddr.String()), | ||
sdk.NewAttribute(types.AttributeKeyAckError, err.Error()), // contains original error message not redacted | ||
sdk.NewAttribute(types.AttributeKeyAckSuccess, "false"), | ||
)) | ||
return channeltypes.NewErrorAcknowledgement(err) | ||
} | ||
return ContractConfirmStateAck(ack) | ||
} | ||
|
||
var _ ibcexported.Acknowledgement = ContractConfirmStateAck{} | ||
|
||
type ContractConfirmStateAck []byte | ||
|
||
func (w ContractConfirmStateAck) Success() bool { | ||
return true // always commit state | ||
} | ||
|
||
func (w ContractConfirmStateAck) Acknowledgement() []byte { | ||
return w | ||
// emit all contract and submessage events on success | ||
ctx.EventManager().EmitEvents(em.Events()) | ||
ctx.EventManager().EmitEvent( | ||
sdk.NewEvent( | ||
types.EventTypePacketRecv, | ||
sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddr.String()), | ||
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), | ||
sdk.NewAttribute(types.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack.Success())), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't know if this us a success or not. It's just bytes from contract that can mean anything. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be This attribute was inspired by the ics-20 impl. At this stage we do know that the ibc packet was successfully handled by the contract (and any sub-messages succeeded). The state will be committed and the Ack data stored. |
||
)) | ||
return ack | ||
} | ||
|
||
// OnAcknowledgementPacket implements the IBCModule interface | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,9 @@ package keeper | |
import ( | ||
"time" | ||
|
||
channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" | ||
ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" | ||
|
||
errorsmod "cosmossdk.io/errors" | ||
wasmvmtypes "github.com/CosmWasm/wasmvm/types" | ||
"github.com/cosmos/cosmos-sdk/telemetry" | ||
|
@@ -116,7 +119,7 @@ func (k Keeper) OnRecvPacket( | |
ctx sdk.Context, | ||
contractAddr sdk.AccAddress, | ||
msg wasmvmtypes.IBCPacketReceiveMsg, | ||
) ([]byte, error) { | ||
) (ibcexported.Acknowledgement, error) { | ||
defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "ibc-recv-packet") | ||
contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr) | ||
if err != nil { | ||
|
@@ -130,13 +133,34 @@ func (k Keeper) OnRecvPacket( | |
res, gasUsed, execErr := k.wasmVM.IBCPacketReceive(codeInfo.CodeHash, env, msg, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas, costJSONDeserialization) | ||
k.consumeRuntimeGas(ctx, gasUsed) | ||
if execErr != nil { | ||
return nil, errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) | ||
panic(execErr) // let contract fully abort IBC receive in certain case | ||
} | ||
if res.Err != "" { // handle error case as before https://github.com/CosmWasm/wasmvm/commit/c300106fe5c9426a495f8e10821e00a9330c56c6 | ||
return nil, errorsmod.Wrap(types.ErrExecuteFailed, res.Err) | ||
if res.Err != "" { | ||
// return error ACK with non-redacted contract message | ||
return channeltypes.Acknowledgement{ | ||
Response: &channeltypes.Acknowledgement_Error{Error: res.Err}, | ||
}, nil | ||
} | ||
// note submessage reply results can overwrite the `Acknowledgement` data | ||
return k.handleContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok.Messages, res.Ok.Attributes, res.Ok.Acknowledgement, res.Ok.Events) | ||
data, err := k.handleContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok.Messages, res.Ok.Attributes, res.Ok.Acknowledgement, res.Ok.Events) | ||
if err != nil { | ||
// submessage errors result in error ACK | ||
return nil, err | ||
} | ||
// success ACK | ||
return ContractConfirmStateAck(data), nil | ||
Comment on lines
+150
to
+151
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this code or comment is misleading because it can be either a success or and error or a non-binary acknowledgement type. We should not try to give it any meaning. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On packet receive, success can be defined as case 1 + 2 of #697 (comment) . The contract was able to fully handle the packet. State will be committed. |
||
} | ||
|
||
var _ ibcexported.Acknowledgement = ContractConfirmStateAck{} | ||
|
||
type ContractConfirmStateAck []byte | ||
|
||
func (w ContractConfirmStateAck) Success() bool { | ||
return true // always commit state | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any documentation what There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The best source for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I raised the issue here: cosmos/ibc-go#3434 |
||
|
||
func (w ContractConfirmStateAck) Acknowledgement() []byte { | ||
return w | ||
} | ||
|
||
// OnAckPacket calls the contract to handle the "acknowledgement" data which can contain success or failure of a packet | ||
|
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.
Is this something where we can provide a better error message than the redacted error too?
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.
Good 👁️ ! Unless we touch our contract-to-port mapping we should never run into this case. Either we
panic
here or we need to return the error event, too.I would prefer panic to make clear in our code that this must not happen. This is not ideal as the packet may be re-submitted until timeout but it is not supposed to happen