-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
APIv2(ledger_entry) : check error #4630
Conversation
Json::Value const jrr = env.rpc( | ||
"json", "ledger_entry", to_string(jvParams))[jss::result]; | ||
|
||
if (apiVersion < 2u) |
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.
nit: why is apiVersion checked with < 2u in this file compared > 1u? seems better to keep consistent throughout codebase (if most files have already established some standard)
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.
In the test file, it is specifically checking results for apiVersion < 2u and apiVersion other than that (>=2) , while in non-test files, the new error codes only execute if apiVersion is greater than 1. There is a guideline already established here:
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 have access to that doc, but thanks for elaboration. If you don't mind sharing it, my email is [email protected]
Is > 1u
in non-test file equivalent to >= 2u
in test file? These seem to always be equivalent expressions since it is impossible to have decimal (1.5) here, right?
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.
yea > 1u in non-test file is equivalent to >= 2u in test file.
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, but comments can be improved.
@@ -51,7 +51,15 @@ doLedgerEntry(RPC::JsonContext& context) | |||
|
|||
if (context.params.isMember(jss::index)) | |||
{ | |||
if (!uNodeIndex.parseHex(context.params[jss::index].asString())) | |||
// Document states "index" field is a string. check for this apiVersion |
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.
What document are you referring to ? xrpl.org ? You can make this clear in the comments and remove ambiguity.
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. Feel free to ignore my minor comments or apply the suggestions - up to you 👍
// apiVersion 2 onwards. invalidParam error is thrown if the above | ||
// condition is false | ||
if (!context.params[jss::nft_page].isString() && | ||
context.apiVersion > 1u) |
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.
minor: You could switch the checks around to save some unnecessary work in case apiVersion is 1
// XRPL Doc states "index" field is a string. check for this apiVersion | ||
// 2 onwards. invalidParam error is thrown if the above condition is | ||
// false | ||
if (!context.params[jss::index].isString() && context.apiVersion > 1u) |
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.
minor: same thing with switching params around
@godexsoft @arihantkothari to review new changes |
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.
👍
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 👍
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.
You made changes to the cases for jss::index
, jss::check
, jss::directory
, and jss::nft_page
, but you only added a test case for jss::check
. As noted below, the change for nft_page
is unnecessary. That aside, you also need to test index
and directory
. However, the directory
case knows how to handle a json object, so you also need to test with something it can't handle: arrays.
// 2 onwards. invalidParam error is thrown if the above condition is | ||
// false |
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.
To be precise, the error is not thrown, it's returned. I think it's worth rewriting this and all the other comments to say, "invalidParam error is returned if the above condition is false.", or even simpler, "invalidParam error is returned if not."
src/test/rpc/LedgerRPC_test.cpp
Outdated
Json::Value checkParams; | ||
checkParams[jss::owner] = "rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU"; | ||
checkParams[jss::ledger_index] = "validated"; | ||
jvParams[jss::check] = checkParams; |
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.
You're reusing the jvParams
from the previous test here, so that contains features
, etc. To guarantee that you're testing what you expect to be testing, start with a new jvParams
.
if (context.params[jss::nft_page].isString()) | ||
{ | ||
// XRPL Doc states "nft_page" field is a string. check for this | ||
// apiVersion 2 onwards. invalidParam error is thrown if the above | ||
// condition is false | ||
if (context.apiVersion > 1u && | ||
!context.params[jss::nft_page].isString()) | ||
{ | ||
uNodeIndex = beast::zero; | ||
jvResult[jss::error] = "invalidParams"; | ||
} |
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.
Line 359 is checking whether nft_page
is a string, so the check on line 365 that it's a string can never fail. In other words, this block is unnecessary.
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.
After posting my previous review, I dug a little further, and ended up going down a rabbit hole.
The original issue that this PR fixes is #4550. The basic problem is that the request is returning an "Internal error" for some bad inputs. The goal is to change that to return "invalidParams".
The question is why is "Internal error" being returned in the first place. Long story short, the Json::Value::asString()
function throws
a Json::error
if the value is actually a Json object or array.
So I went through doLedgerEntry
and looked for every unchecked call to asString
. There were actually about a dozen more that were not handled in the original PR. I also expanded the unit tests to check all of those cases, including verifying that the checked calls to asString
returned something other than "Internal error". That commit is here. ximinez@4c9bb17 (Feel free to cherry-pick that onto your branch.)
But then I looked over the whole change set and was really unhappy with all of these piecemeal checks.
There's a much cleaner way to do it, which eliminates the worry of missing any cases and is future-proof (in case later lookups neglect some of those checks). Just catch the thrown Json::error
once. Here's that commit: dbe7c5c (Feel free to cherry-pick that one, too, but you'll have to grab the first one to merge cleanly. Or just merge the branch.)
It's much prettier if you hide whitespace changes.
@ximinez Thank you for all the insight! 😄. I pretty much cherry-picked the try-catch and unittest. I agree it's a LOT cleaner this way and prevents future errors to occur. |
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
@godexsoft @arihantkothari - this PR has changed since the time you reviewed it. Could you have a look at the latest? |
The diff generated by github for this PR is horrible, very hard to understand what the actual changes are. My 2c:
Since @ximinez is happy with the change I have no objections. |
Click the gear at the top of the diff, and check "Hide whitespace", then click "Apply and reload". Makes a huge difference on diffs like this.
Sometimes it's a great practice, especially when you're dealing with user input, because you never know what kind of wacky input a user is going to send you, and trying to guess everything a user can do wrong can make the code a lot more complex and hard to read. Compare that to a Besides, like you said, we already have exception handling - that's what returns the "Internal error" in the current version. This change just puts a prettier error on it. |
@ximinez Thanks for the nifty trick to make the diff more readable! In my opinion, user input is not a good place for using exceptions but as i said, they are sometimes a necessary evil, especially if your codebase is already relying on them. My point is - the way to simplify code is thru abstractions that can be tested separately and hide irrelevant details. |
note: updates |
) - Verify "check", used to retrieve a Check object, is a string. - Verify "nft_page", used to retrieve an NFT Page, is a string. - Verify "index", used to retrieve any type of ledger object by its unique ID, is a string. - Verify "directory", used to retrieve a DirectoryNode, is a string or an object. This change only impacts api_version 2 since it is a breaking change. https://xrpl.org/ledger_entry.html Fix XRPLF#4550
) - Verify "check", used to retrieve a Check object, is a string. - Verify "nft_page", used to retrieve an NFT Page, is a string. - Verify "index", used to retrieve any type of ledger object by its unique ID, is a string. - Verify "directory", used to retrieve a DirectoryNode, is a string or an object. This change only impacts api_version 2 since it is a breaking change. https://xrpl.org/ledger_entry.html Fix XRPLF#4550
) - Verify "check", used to retrieve a Check object, is a string. - Verify "nft_page", used to retrieve an NFT Page, is a string. - Verify "index", used to retrieve any type of ledger object by its unique ID, is a string. - Verify "directory", used to retrieve a DirectoryNode, is a string or an object. This change only impacts api_version 2 since it is a breaking change. https://xrpl.org/ledger_entry.html Fix XRPLF#4550
) - Verify "check", used to retrieve a Check object, is a string. - Verify "nft_page", used to retrieve an NFT Page, is a string. - Verify "index", used to retrieve any type of ledger object by its unique ID, is a string. - Verify "directory", used to retrieve a DirectoryNode, is a string or an object. This change only impacts api_version 2 since it is a breaking change. https://xrpl.org/ledger_entry.html Fix XRPLF#4550
High Level Overview of Change
Fix issue #4550 on ledger entry
Context of Change
"check" field is verified to be a string. (Check the above Github issue link for more info.) Everything is under API Version 2 as it is a breaking change.
Type of Change
Added own unit test for API Version 2;