-
Notifications
You must be signed in to change notification settings - Fork 92
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
feat: add 'Data' field to 'respError' struct #123
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #123 +/- ##
=========================================
Coverage ? 71.38%
=========================================
Files ? 12
Lines ? 1957
Branches ? 0
=========================================
Hits ? 1397
Misses ? 459
Partials ? 101
|
I think we will need more changes here for the library to determine if the error has data and to read it from the error but we can worry about it when we get blocked by it. We'll find out more when we do the Lotus work. Update Lotus to use this |
@aarshkshah1992 As per the @Stebalien comments : https://filecoinproject.slack.com/archives/CP50PPW2X/p1728439741305709?thread_ts=1727699414.185139&cid=CP50PPW2X We tried to add |
@akaladarshi Before I review this -> can you guys post a snippet of the errors you see for contract reverts when calling via JSON RPC on a Calibnet node ? |
@aarshkshah1992 so we hardcoded the |
errors.go
Outdated
} | ||
|
||
// DataError contains extra data to explain the error | ||
type DataError interface { |
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.
ErrorWithData
errors.go
Outdated
@@ -58,3 +58,15 @@ type marshalable interface { | |||
json.Marshaler | |||
json.Unmarshaler | |||
} | |||
|
|||
// Error wraps RPC errors, which contain an error code in addition to the message. | |||
type Error interface { |
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 do we need this interface ?
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.
Added so we can have custom error codes.
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 do we need custom error codes ? Can you write a bit explaining what made you add this ? Was it something you saw during your testing ?
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.
Also this needs a better name. This can be ErrorWithCode
and the below can be ErrorWithData
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.
@aarshkshah1992 I think this will give more idea towards the error codes: filecoin-project/lotus#12553
handler.go
Outdated
@@ -69,6 +70,7 @@ type respError struct { | |||
Code ErrorCode `json:"code"` | |||
Message string `json:"message"` | |||
Meta json.RawMessage `json:"meta,omitempty"` | |||
Data interface{} `json:"data,omitempty"` |
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 interface{}
?
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.
@aarshkshah1992 I posted a comment above in current PR regarding this: #123 (comment)
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.
Can we make this just a string ? Why does it have to be json.RawMessage
or interface{}
@rvagg -> Any thoughts ?
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.
https://www.jsonrpc.org/specification#error_object
A Primitive or Structured value that contains additional information about the error.
🤷 interface{}
would seem more accurate, as long as it's serialisable
handler.go
Outdated
} | ||
} | ||
|
||
var err2 Error | ||
if errors.As(err, &err2) { | ||
out.Code = ErrorCode(err2.ErrorCode()) |
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 are we setting the code here again ? Don't we already have it on line 355 above ?
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.
@aarshkshah1992
So in line 355 we are setting the registered error codes, but here we are setting the custom error code.
I think we can directly register the code
for ErrWithExecutionReverted
, but then we need to finalise on which code to use, as error code 3
is already registered with the ActorNotFound
handler.go
Outdated
@@ -504,10 +524,17 @@ func (s *handler) handle(ctx context.Context, req request, w func(func(io.Writer | |||
|
|||
log.Warnf("failed to setup channel in RPC call to '%s': %+v", req.Method, err) | |||
stats.Record(ctx, metrics.RPCResponseError.M(1)) | |||
resp.Error = &respError{ | |||
respErr := &respError{ |
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.
Don't we need to do the same thing in the rpcError
function in server.go ?
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.
Probably not as rpcErr
is only used for RPC processing errors and not errors returned by the invocation of the function.
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.
I am not sure about this because rpcError
function is returning errors specific to RPCs (method not found etc), but the actual execution error is inside the handle
function after doCall
here:
Line 450 in c185272
callResult, err := doCall(req.Method, handler.handlerFunc, callParams) |
@rvagg Please can you 👁️ this ? |
some tests for this in here would be good |
response.go
Outdated
var ( | ||
_ error = (*JSONRPCError)(nil) | ||
marshalableRT = reflect.TypeOf(new(marshalable)).Elem() | ||
unmarshalableRT = reflect.TypeOf(new(RPCErrorCodec)).Elem() |
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.
unmarshalableRT = reflect.TypeOf(new(RPCErrorCodec)).Elem() | |
errorCodecRT = reflect.TypeOf(new(RPCErrorCodec)).Elem() |
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.
Done.
response.go
Outdated
v = reflect.New(t) | ||
} | ||
|
||
if v.Type().Implements(unmarshalableRT) { |
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.
if v.Type().Implements(unmarshalableRT) { | |
if v.Type().Implements(errorCodecRT) { |
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.
Updated.
response.go
Outdated
} | ||
|
||
if v.Type().Implements(unmarshalableRT) { | ||
_ = v.Interface().(RPCErrorCodec).FromJSONRPCError(*e) |
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.
if we get an error here (and in the block below for UnmarshalJSON), we should:
log.Warnf
- return
reflect.ValueOf(e)
because we can't know that we have a properly instantiated converted error type
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.
Done.
response.go
Outdated
|
||
if len(e.Meta) > 0 && v.Type().Implements(marshalableRT) { | ||
if err := v.Interface().(marshalable).UnmarshalJSON(e.Meta); err != nil { | ||
log.Errorf("Error unmarshaling metadata for error type '%s': %w", t.String(), err) |
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.
log.Errorf("Error unmarshaling metadata for error type '%s': %w", t.String(), err) | |
log.Errorf("Error unmarshalling error metadata to custom error type '%s' (code %d): %w", t.String(), e.Code, err) |
response.go
Outdated
|
||
if v.Type().Implements(errorCodecRT) { | ||
if err := v.Interface().(RPCErrorCodec).FromJSONRPCError(*e); err != nil { | ||
log.Errorf("Error converting JSONRPCError (code %d) to custom error type '%s': %w", e.Code, t.String(), err) |
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.
log.Errorf("Error converting JSONRPCError (code %d) to custom error type '%s': %w", e.Code, t.String(), err) | |
log.Errorf("Error converting JSONRPCError to custom error type '%s' (code %d): %w", t.String(), e.Code, err) |
response.go
Outdated
} | ||
|
||
if len(e.Meta) > 0 && v.Type().Implements(marshalableRT) { |
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.
} | |
if len(e.Meta) > 0 && v.Type().Implements(marshalableRT) { | |
} else if len(e.Meta) > 0 && v.Type().Implements(marshalableRT) { |
let's disallow dual behaviour for now, we could enable this at some point if there was ever a case for it (I can't think what it would be) but best avoid surprises if we're not testing for it
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.
Done.
handler.go
Outdated
resp.Error = &respError{ | ||
|
||
respErr := &JSONRPCError{ | ||
Code: 1, | ||
Message: err.Error(), | ||
} | ||
|
||
if m, ok := err.(RPCErrorCodec); ok { | ||
rpcErr, err := m.ToJSONRPCError() | ||
if err != nil { | ||
log.Warnf("Failed to convert error to JSONRPCError: %v", err) | ||
} else { | ||
respErr.Data = rpcErr.Data | ||
} | ||
} | ||
|
||
resp.Error = respErr |
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.
This is unnecessary, we only ever get back an internal error at this point which is why code 1 is being used as the internal error code (custom codes start at 2). You can follow this case down in to websocket.go handleChanOut
. So all you need to do here is s/respError/JSONRPCError/
and leave the rest alone.
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.
I will remove this from here, wdym by when you say You can follow this case down in to websocket.go handleChanOut
. I don't see any error in the response there.
handler.go
Outdated
case RPCErrorCodec: | ||
o, err := m.ToJSONRPCError() | ||
if err != nil { | ||
log.Warnf("Failed to convert error to JSONRPCError: %v", err) |
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.
let's Errorf
these two as well, if they're not converting then it's either a programmer error or a system error (like OOM)
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.
Done.
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.
looks good, just a few minor changes and this is good to ship I think
well done @virajbhartiya & @akaladarshi, nice work on this one |
This pull request includes a small change to the
handler.go
file. The change adds an optionalData
field to therespError
struct. This is done so as to implement changes mentioned in filecoin-project/lotus#10311handler.go
: AddedData
field to therespError
struct to include additional error information.