-
Notifications
You must be signed in to change notification settings - Fork 106
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
fix(rpc): Refactor getrawtransaction
& RPC error handling
#9049
base: main
Are you sure you want to change the base?
Conversation
We don't need such a test anymore because the deserialization is handled by Serde now.
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 looking good so far, I left an optional suggestion about matching zcashd's output when a transaction is found in a side chain.
I'd like to review the changes to the get_block()
method against #9006 if we can target this PR against the get-block
branch (or wait for #9006 to merge and rebase off of main).
/// A trait for mapping errors to [`jsonrpc_core::Error`]. | ||
pub(crate) trait MapError<T> { | ||
/// Maps errors to [`jsonrpc_core::Error`] with a specific error code. | ||
fn map_error( | ||
self, | ||
code: impl Into<jsonrpc_core::ErrorCode>, | ||
) -> std::result::Result<T, jsonrpc_core::Error>; | ||
} | ||
|
||
/// A trait for conditionally converting a value into a `Result<T, jsonrpc_core::Error>`. | ||
pub(crate) trait OkOrError<T> { | ||
/// Converts the implementing type to `Result<T, jsonrpc_core::Error>`, using an error code and | ||
/// message if conversion is to `Err`. | ||
fn ok_or_error( | ||
self, | ||
code: impl Into<jsonrpc_core::ErrorCode>, | ||
message: impl ToString, | ||
) -> std::result::Result<T, jsonrpc_core::Error>; | ||
} |
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.
Error constructor methods for commonly-used error codes (or just Misc
) could be nice here.
/// A trait for mapping errors to [`jsonrpc_core::Error`]. | |
pub(crate) trait MapError<T> { | |
/// Maps errors to [`jsonrpc_core::Error`] with a specific error code. | |
fn map_error( | |
self, | |
code: impl Into<jsonrpc_core::ErrorCode>, | |
) -> std::result::Result<T, jsonrpc_core::Error>; | |
} | |
/// A trait for conditionally converting a value into a `Result<T, jsonrpc_core::Error>`. | |
pub(crate) trait OkOrError<T> { | |
/// Converts the implementing type to `Result<T, jsonrpc_core::Error>`, using an error code and | |
/// message if conversion is to `Err`. | |
fn ok_or_error( | |
self, | |
code: impl Into<jsonrpc_core::ErrorCode>, | |
message: impl ToString, | |
) -> std::result::Result<T, jsonrpc_core::Error>; | |
} | |
/// A trait for mapping errors to [`jsonrpc_core::Error`]. | |
pub(crate) trait MapError<T>: Sized { | |
/// Maps errors to [`jsonrpc_core::Error`] with a specific error code. | |
fn map_error( | |
self, | |
code: impl Into<jsonrpc_core::ErrorCode>, | |
) -> std::result::Result<T, jsonrpc_core::Error>; | |
/// Maps errors to [`jsonrpc_core::Error`] with a [`LegacyCode::Misc`] error code. | |
fn map_misc_error(self) -> std::result::Result<T, jsonrpc_core::Error> { | |
self.map_error(LegacyCode::Misc) | |
} | |
} | |
/// A trait for conditionally converting a value into a `Result<T, jsonrpc_core::Error>`. | |
pub(crate) trait OkOrError<T>: Sized { | |
/// Converts the implementing type to `Result<T, jsonrpc_core::Error>`, using an error code and | |
/// message if conversion is to `Err`. | |
fn ok_or_error( | |
self, | |
code: impl Into<jsonrpc_core::ErrorCode>, | |
message: impl ToString, | |
) -> std::result::Result<T, jsonrpc_core::Error>; | |
/// Converts the implementing type to `Result<T, jsonrpc_core::Error>`, using a [`LegacyCode::Misc`] error code. | |
fn ok_or_misc_error( | |
self, | |
message: impl ToString, | |
) -> std::result::Result<T, jsonrpc_core::Error> { | |
self.ok_or_error(LegacyCode::Misc, message) | |
} | |
} |
fn get_raw_transaction( | ||
&self, | ||
txid_hex: String, | ||
HexData(txid): HexData, |
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 could be typed as a transaction::Hash
(which implements ToHex
& FromHex
), though it may return the wrong error code that way.
.ready() | ||
.and_then(|service| service.call(request)) | ||
.and_then(|service| service.call(zebra_state::ReadRequest::Transaction(txid))) |
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.
Optional: To match zcashd's output when a transaction is on a side chain, we either need a new request to check for transactions on side chains, or to update this request so that it checks side chains for the transaction id too and returns an enum variant indicating whether the transaction was found on the best chain or a side chain.
Motivation
Close #8945.
Specifications & References
Solution
getrawtransaction
output conflicts withzcashd
output #8744. Note thatzcashd
stores transactions in orphaned blocks and responds to queries requesting such transactions withheight
to -1. Since Zebra doesn't keep orphaned blocks below the rollback limit, it now returns the error "No such mempool or blockchain transaction". If we wanted to matchzcashd
, we'd need to start storing orphaned blocks.getrawtransaction
and some other RPCs.HexData
instead ofString
s ingetrawtransaction
.Network
s.Tests
Update and add
to check the new error codes.
Follow-up Work
PR Author's Checklist
PR Reviewer's Checklist