-
Notifications
You must be signed in to change notification settings - Fork 138
rfq+rfqmsg: add structured price oracle error codes #1766
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
base: main
Are you sure you want to change the base?
Changes from 8 commits
3a7986f
f58d19e
2f096e2
b9b018a
bbd3afe
5274aaf
e875f5a
6bdb36a
aef763a
6130dac
79308a2
6ff7217
5eaf8a9
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 rfq | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"sync" | ||
"time" | ||
|
@@ -146,10 +147,9 @@ | |
} | ||
|
||
// Now we will check for an error in the response from the price oracle. | ||
// If present, we will convert it to a string and return it as an error. | ||
// If present, we will simply relay it. | ||
if oracleResponse.Err != nil { | ||
return nil, fmt.Errorf("failed to query price oracle for "+ | ||
"buy price: %s", oracleResponse.Err) | ||
return nil, oracleResponse.Err | ||
jtobin marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
} | ||
|
||
// By this point, the price oracle did not return an error or a buy | ||
|
@@ -282,10 +282,9 @@ | |
} | ||
|
||
// Now we will check for an error in the response from the price oracle. | ||
// If present, we will convert it to a string and return it as an error. | ||
// If present, we will simply relay it. | ||
if oracleResponse.Err != nil { | ||
return nil, fmt.Errorf("failed to query price oracle for "+ | ||
"sell price: %s", oracleResponse.Err) | ||
return nil, oracleResponse.Err | ||
} | ||
|
||
// By this point, the price oracle did not return an error or a sell | ||
|
@@ -372,10 +371,12 @@ | |
peerID, request.PriceOracleMetadata, IntentRecvPayment, | ||
) | ||
if err != nil { | ||
// Send a reject message to the peer. | ||
// Construct an appropriate RejectErr based on | ||
// the oracle's response, and send it to the | ||
// peer. | ||
msg := rfqmsg.NewReject( | ||
request.Peer, request.ID, | ||
rfqmsg.ErrUnknownReject, | ||
createCustomRejectErr(err), | ||
) | ||
sendOutgoingMsg(msg) | ||
|
||
|
@@ -473,10 +474,12 @@ | |
peerID, request.PriceOracleMetadata, IntentPayInvoice, | ||
) | ||
if err != nil { | ||
// Send a reject message to the peer. | ||
// Construct an appropriate RejectErr based on | ||
// the oracle's response, and send it to the | ||
// peer. | ||
msg := rfqmsg.NewReject( | ||
request.Peer, request.ID, | ||
rfqmsg.ErrUnknownReject, | ||
createCustomRejectErr(err), | ||
) | ||
sendOutgoingMsg(msg) | ||
|
||
|
@@ -495,6 +498,36 @@ | |
return nil | ||
} | ||
|
||
// createCustomRejectErr creates a RejectErr with code 0 and a custom message | ||
// based on an error response from a price oracle. | ||
func createCustomRejectErr(err error) rfqmsg.RejectErr { | ||
var oracleError *OracleError | ||
|
||
if errors.As(err, &oracleError) { | ||
// The error is of the expected type, so switch on the error | ||
// code returned by the oracle. If the code is benign, then the | ||
// RejectErr will simply relay the oracle's message. Otherwise, | ||
|
||
// we'll return an opaque rejection message. | ||
switch oracleError.Code { | ||
|
||
// The rejection message will state that the oracle doesn't | ||
// support the asset. | ||
case ErrUnsupportedOracleAsset: | ||
|
||
msg := oracleError.Msg | ||
return rfqmsg.ErrRejectWithCustomMsg(msg) | ||
|
||
// The rejection message will be opaque, with the error | ||
// unspecified. | ||
default: | ||
return rfqmsg.ErrUnknownReject | ||
} | ||
} else { | ||
// The error is of an unexpected type, so just return an opaque | ||
// error message. | ||
return rfqmsg.ErrUnknownReject | ||
} | ||
} | ||
|
||
// HandleOutgoingSellOrder handles an outgoing sell order by constructing sell | ||
// requests and passing them to the outgoing messages channel. These requests | ||
// are sent to peers. | ||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -86,12 +86,26 @@ const ( | |||||||
// service. | ||||||||
type OracleError struct { | ||||||||
// Code is a code which uniquely identifies the error type. | ||||||||
Code uint8 | ||||||||
Code OracleErrorCode | ||||||||
|
||||||||
// Msg is a human-readable error message. | ||||||||
Msg string | ||||||||
} | ||||||||
|
||||||||
// OracleErrorCode uniquely identifies the kinds of error an oracle may | ||||||||
// return. | ||||||||
type OracleErrorCode uint8 | ||||||||
|
||||||||
const ( | ||||||||
// ErrUnspecifiedOracleError represents the case where the oracle has | ||||||||
// declined to give a more specific reason for the error. | ||||||||
ErrUnspecifiedOracleError OracleErrorCode = iota | ||||||||
jtobin marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||
|
||||||||
// ErrUnsupportedOracleAsset represents the case in which an oracle does | ||||||||
// not provide quotes for the requested asset. | ||||||||
ErrUnsupportedOracleAsset | ||||||||
) | ||||||||
|
||||||||
// Error returns a human-readable string representation of the error. | ||||||||
func (o *OracleError) Error() string { | ||||||||
// Sanitise price oracle error message by truncating to 255 characters. | ||||||||
|
@@ -356,7 +370,8 @@ func (r *RpcPriceOracle) QuerySellPrice(ctx context.Context, | |||||||
|
||||||||
return &OracleResponse{ | ||||||||
Err: &OracleError{ | ||||||||
Msg: result.Error.Message, | ||||||||
Msg: result.Error.Message, | ||||||||
Code: marshallErrorCode(result.Error.Code), | ||||||||
}, | ||||||||
}, nil | ||||||||
|
||||||||
|
@@ -365,6 +380,19 @@ func (r *RpcPriceOracle) QuerySellPrice(ctx context.Context, | |||||||
} | ||||||||
} | ||||||||
|
||||||||
// marshallErrorCode marshalls an over-the-wire error code into an | ||||||||
// OracleErrorCode. | ||||||||
func marshallErrorCode(code oraclerpc.ErrorCode) OracleErrorCode { | ||||||||
switch code { | ||||||||
case oraclerpc.ErrorCode_ERROR_UNSPECIFIED: | ||||||||
return ErrUnspecifiedOracleError | ||||||||
case oraclerpc.ErrorCode_ERROR_UNSUPPORTED: | ||||||||
|
case oraclerpc.ErrorCode_ERROR_UNSUPPORTED: | |
case oraclerpc.ErrorCode_ERROR_UNSUPPORTED: |
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.
except for the first case (but including the default
case below)
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -92,6 +92,15 @@ var ( | |
} | ||
) | ||
|
||
// ErrRejectWithCustomMsg produces the "unknown" error code, but pairs | ||
// it with a custom error message. | ||
func ErrRejectWithCustomMsg(msg string) RejectErr { | ||
return RejectErr{ | ||
Code: 0, | ||
|
||
Msg: msg, | ||
} | ||
} | ||
|
||
const ( | ||
// latestRejectVersion is the latest supported reject wire message data | ||
// field version. | ||
|
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 there an enum val from our lib that we can use here instead of
1
?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 used a raw '1' at present to avoid updating the mock oracle's dependencies (it looks like there have been other RPC changes since it was last updated as well). Perhaps best to avoid changing the mock oracle for now, and just update it to use the latest RPC definitions in another PR?
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 you agree, I'll drop the commit that changes the mock oracle before merge.)
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 think that if we want to go ahead and update this price oracle it should include a version bump too.
Having said that, I believe it's okay to just leave the
Code
field unspecified and let it default to0
, in order to not have to populate it with magic numbersThere 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 think updating the mock oracle in a separate PR makes sense to me. We can wait until 0.7 for example.
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.
Yeah, let's update the mock oracle in a separate PR. 👍