-
Notifications
You must be signed in to change notification settings - Fork 635
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
Use ErrorReceipt as Error type #3689
Comments
Here's how I imagine things:
if err := func(); err != nil {
return types.NewErrorReceipt(err)
}
if ok := err.(types.ErrorReceipt); ok {
abortUpgradeHandsahke(err)
}
ctx.Log(errorReceipt.FullError())
emitErrorReceiptEvent()
// restore channel ensure non-determinstic info is discarded from Message field
errorReceipt = types.NewErrorReceipt(channel.Sequence, err)
k.SetErrorReceipt(errorReceipt) One part I'm unsure about, in the initial return, I think it is nice for it to look like a normal error type (just with a ErrorReceipt prefix), but I would like to do logs/emit events later in the restore channel function. So creating an API which creates an error receipt type that has full non-determinstic error info that can then be converted into the verifiable error receipt type This is just my ideal handling, open to other ideas |
Should the actual emission of events / setting error receipt happen in the restore function? I was thinking something like // msgServer
err := ChanUpgradeTry(...)
if isErrReceipt(err) {
abortUpgradeHandshake(err)
return ...
}
func abortUpgradeHandshake(err) {
log(err)
restoreChannel()
emitErrorReceiptEvent(err)
} I'm not sure the setting of an error receipt should be coupled with the act of restoring, I think logically it makes sense that we restore, and then write an error receipt as two concrete actions. (which may end up in a function like abortUpgradeHandshake ) Maybe I am misinterpreting your pseudo code. |
Looking a little more into it, if we want to be able to maintain both the original error message (for logs & events) while also being able to deterministically determine the message for the // UpgradeError defines an error that occurs during an upgrade.
type UpgradeError struct {
// underlyingError is the underlying error that caused the upgrade to fail.
// this error should not be written to state.
underlyingError error
// upgradeSequence is the sequence number of the upgrade that failed.
upgradeSequence uint64
}
func (u *UpgradeError) Error() string {
return u.underlyingError.Error()
}
// GetErrorReceipt returns an error receipt with the code from the underlying error type stripped.
func (u *UpgradeError) GetErrorReceipt() ErrorReceipt {
_, code, _ := errorsmod.ABCIInfo(u.underlyingError, false) // discard non-determinstic codespace and log values
return ErrorReceipt{
Sequence: u.upgradeSequence,
Message: fmt.Sprintf("ABCI code: %d: %s", code, restoreErrorString),
}
}
// NewUpgradeError returns a new UpgradeError instance.
func NewUpgradeError(upgradeSequence uint64, err error) UpgradeError {
return UpgradeError{
underlyingError: err,
upgradeSequence: upgradeSequence,
}
} WDYT @colin-axner ? |
I love it! @damiannolan recommended removing the |
Summary
As demonstated in #3418, use the ErrorReceipt as an Error type, so all our API's which return an
error
can return anErrorReceipt
. Once the msg server receives theErrorReceipt
it can callabortUpgradeHandshake
which does app callbacks and writes the error receiptI like this flow because it makes it very clear to the msg server when the handshake should be aborted and when it succeeded, otherwise a nil error could be returned by
channelKeeper.ChanUpgradeTry
even though the handshake should not continueFor Admin Use
The text was updated successfully, but these errors were encountered: