-
Notifications
You must be signed in to change notification settings - Fork 339
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
Surface bitcoind rpc error information #2057
Conversation
let message = error["message"].as_str().unwrap_or("unknown error"); | ||
return Err(std::io::Error::new(std::io::ErrorKind::Other, message)); | ||
let rpc_error = RpcError { | ||
code: error["code"].as_i64().unwrap_or(-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.
Should we make RpcError::code
an Option
given -1
is RPC_MISC_ERROR
? Possibly the same for message
.
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 I guess we could do that. I'm not sure what case (if ever) it won't have a code and message. I purposefully mapped it to RPC_MISC_ERROR since that's sort of what it is but happy to do it as Option's too if you think that makes more sense.
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.
maybe it'd be a little cleaner to make RpcError an enum with a struct variant and an "Unknown" variant when there's no code/message 🤷♂️
I guess you don't gain much, still need to do a match to find out error code
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 keep it as is. Like you said, it probably shouldn't ever happen and the code is used as a catch-all for when the RPC handling code throws an exception in Core.
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.
Ok, Matt had made a comment that we should probably just use a new RpcError enum that wraps the io Error. think it’s worth just doing that?
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.
That's a much larger change and is orthogonal, IMO, if you're just trying to include an extra piece of data. Changing the error type here means would make it inconsistent with RestCleint
, and you'd ultimately need to wrap it again at the BlockSourceError
level, anyhow, unless you want to change that as well. But that already is an enum.
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, that makes sense. I was trying to avoid having to deal with a cascade of changes like that. If we're okay with this solution then it would work for what we needed (access to bitcoind error code)
Oh, could you update the commit message with context? We should make sure it's there independent of Github. |
@@ -68,9 +87,11 @@ impl RpcClient { | |||
|
|||
let error = &response["error"]; | |||
if !error.is_null() { | |||
// TODO: Examine error code for a more precise std::io::ErrorKind. |
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.
Looking into this a little more, I think the idea was that some errors may be considered transient while others are persistent. And this would affect the conversion done here:
rust-lightning/lightning-block-sync/src/convert.rs
Lines 21 to 29 in 8311581
impl From<std::io::Error> for BlockSourceError { | |
fn from(e: std::io::Error) -> BlockSourceError { | |
match e.kind() { | |
std::io::ErrorKind::InvalidData => BlockSourceError::persistent(e), | |
std::io::ErrorKind::InvalidInput => BlockSourceError::persistent(e), | |
_ => BlockSourceError::transient(e), | |
} | |
} | |
} |
This let's the user know if they should give-up or retry.
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.
Ah ok, that makes sense. Well I can put the TODO back. Seems like to actually impl the TODO we would need to map the error rpc error codes into buckets for persistent vs transient.
Users of the RpcClient had no way to access the error code returned by bitcoind's rpc. We embed a new RpcError struct as the inner error for the returned io::Error. Users can access both the code and the message using this inner struct.
5b39220
to
a7af24b
Compare
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.
LGTM with further specifying ErrorKind
in a future PR.
Note that we currently check that the error contains some message strings in the sample client: https://github.com/lightningdevkit/ldk-sample/blob/e1a87a7e8533bb666ed8002032b124e628da8e12/src/bitcoind_client.rs#L261-L267 This should still work, but we may want to check the error code instead assuming that makes sense. |
I'm not really sure how we expect users to use this - in one specific case we happen to return a field inside the |
Currently the RpcClient only surfaces bitcoind's rpc error message but not the error code. The code is useful downstream to more reliably understand what went wrong.
This creates a new struct RpcError that holds the code and message and then provides that as the inner payload to std::io::Error that is already being returned.