-
Notifications
You must be signed in to change notification settings - Fork 38.7k
bitcoin-cli: Eliminate "Error parsing JSON" errors #15448
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
Conversation
Just pass arguments that can't be parsed as JSON as string arguments. If the RPC method isn't expecting a string argument, this will result in more specific errors from the RPC. And if it allows an argument to be a string as one possible type (for example the `hash_or_height` argument to `getblockstats`), this avoids the need for bitcoin-cli users to use double JSON quoting+shell quoting to pass the string.
|
I think this approach is fine, unless there is an use case where the end result would be really bad - which I don't believe there is. Concept ACK from me. |
|
If this is conceptually ACKed, the now unused |
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.
Tested ACK 45c743
This is effectively moving the type check from the client to the server (unparsable json will get send as string). I guess this is fine
# type check is moved to server
$ for i in {master,45c743}; do ./src/bitcoin-cli-$i -regtest getrawtransaction ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff True ffff ; done
error: Error parsing JSON:True
error code: -1
error message:
JSON value is not a boolean as expected
# test conversion
$ for i in {master,45c743}; do ./src/bitcoin-cli-$i -regtest echojson true 1 '"str"' '[1,2]' '{"a":1}' ; done
[
true,
1,
"str",
[
1,
2
],
{
"a": 1
}
]
[
true,
1,
"str",
[
1,
2
],
{
"a": 1
}
]
# test no conversion
$ for i in {master,45c743}; do ./src/bitcoin-cli-$i -regtest echo true 1 '"str"' '[1,2]' '{"a":1}' ; done
[
"true",
"1",
"\"str\"",
"[1,2]",
"{\"a\":1}"
]
[
"true",
"1",
"\"str\"",
"[1,2]",
"{\"a\":1}"
]
# test conversion with invalid json
$ for i in {master,45c743}; do ./src/bitcoin-cli-$i -regtest echojson True ; done
error: Error parsing JSON:True
[
"True"
]
|
|
||
| if (!rpcCvtTable.convert(strMethod, idx)) { | ||
| UniValue json_value; | ||
| if (!rpcCvtTable.convert(strMethod, idx) || !json_value.read(strVal)) { |
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.
Seems odd to have two inversions in a condition. Would be easier to write
if convert() and read():
# push back parsed value
else:
# push back strThere 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.
Keep diff small? 👼 But agree.
Agree. This matches a common frontend validation pattern: The server must validate and reject garbage. (1) Thus one option is to lean on the remote server to perform that validation. However, it is often better UX -- and potentially saves users $$ in bandwidth, and saves server CPU cycles -- to (2) avoid sending data the client can prove, via its own validation, is known garbage data. Yes, this is double validation; but the 90+% common case is rejected on the client side, remaining efficient by sending no garbage over the network. |
|
Will wait for concept acks & nacks before working more on this. To summarize comments so far: Advantages of this change
Disadvantages of this change
Potential followups
|
|
I don't think we should be optimizing for bandwidth in the error case, which can only happen when a developer debugs locally. |
|
Concept ACK In this case I think we should optimise for user-friendliness. |
|
Concept ACK |
|
I'm kind of skeptical about this, to be honest. I prefer strong validation both client and server side, from my experience, lazy "anything goes" validation (in this case "let the server sort them out") has resulted in quite some unexpected disasters. At the least it makes it harder to reason about what things will do, in advance. |
|
Looks like this removed all remaining calls to |
promag
left a 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.
ACK 45c7439, above comment #15448 (comment) looks good.
Should have python test for new bitcoin-cli behavior.
👍
has resulted in quite some unexpected disasters.
@laanwj like what? Preventing disasters and client validation sound like 2 different things and pretty much unrelated. But better safe than sorry? No strong opinion.
|
|
||
| if (!rpcCvtTable.convert(strMethod, idx)) { | ||
| UniValue json_value; | ||
| if (!rpcCvtTable.convert(strMethod, idx) || !json_value.read(strVal)) { |
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.
Keep diff small? 👼 But agree.
|
|
||
| if (!rpcCvtTable.convert(strMethod, name)) { | ||
| UniValue json_value; | ||
| if (!rpcCvtTable.convert(strMethod, name) || !json_value.read(value)) { |
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.
Same as above.
Defense in depth, belt and suspenders, etc. I mean the underlying issue is that there is an ambiguity, and resolving this ambiguity is here moved from the client to the server, which isn't always better. It's better if both the client and server know what the interpretation of some value is. SQL injection attacks are a well-known problem that is caused by trusting that the server will the right thing when you just pass the value as-is. |
7099984 rpc: doc: Fix and extend getblockstats examples (Adam Soltys) Pull request description: This pull fixes the example curl command for `getblockstats` which doesn't work as is because it's missing a comma between the params and has single quotes around the second parameter. It also adds an additional example of getting block stats by hash by using a known workaround (#15412) to get bitcoin-cli to treat the hash parameter as JSON instead of a string since there is ongoing deliberation about how or whether to fix the root issue (#15448). ACKs for top commit: theStack: ACK 7099984 Tree-SHA512: 84a5b7f449f06fff785bc0afbc1a7dfd55454bc76c52a8945e91556f87f3edfdc5a1780faab8fcfd6c415b734295b7c67d2e04ba7b6cfa91a77758af5dda53ae
Just pass arguments that can't be parsed as JSON as string arguments. If the RPC method isn't expecting a string argument, this will result in more specific errors from the RPC. And if it allows an argument to be a string as one possible type (for example the `hash_or_height` argument to `getblockstats`), this avoids the need for bitcoin-cli users to use double JSON quoting+shell quoting to pass the string. This is a port of bitcoin/bitcoin#15448 Includes several adaptations by Andrea Suisani: - Remove unused ParseNonRFCJSONValue and related unit tests - Avoid double inversion in the same if condition - Functional test adaptation Merge #15488: bitcoin-cli: Eliminate "Error parsing JSON" errors Test plan: - On a version without this patch (!446), run `bitcoin-cli getblockstats 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f` (passing the hash value without quotes ), and observe you get the following error message from the command line program: `error: Error parsing JSON:000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f` - On a version with this patch, run the above command and you should get block statistics JSON output instead of the error message. - Run `test/functional/test_runner.py interface_bitcoin_cli_getblockstats` - it should pass.
|
@laanwj this just pretends the client typed @ryanofsky just wrote 4c19cf5 but then I've realised it's pretty much the same as this. |
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
That's my problem with it "pretends the client typed". If it is purely a user-facing tool like a GUI it might be different (still, it's often better not to guess at intent). The problem is that tools like this are also used in scripts and such, and they might deal with (partially) untrusted input. I think determinism and predictability is very important in input processing. |
7099984 rpc: doc: Fix and extend getblockstats examples (Adam Soltys) Pull request description: This pull fixes the example curl command for `getblockstats` which doesn't work as is because it's missing a comma between the params and has single quotes around the second parameter. It also adds an additional example of getting block stats by hash by using a known workaround (bitcoin#15412) to get bitcoin-cli to treat the hash parameter as JSON instead of a string since there is ongoing deliberation about how or whether to fix the root issue (bitcoin#15448). ACKs for top commit: theStack: ACK bitcoin@7099984 Tree-SHA512: 84a5b7f449f06fff785bc0afbc1a7dfd55454bc76c52a8945e91556f87f3edfdc5a1780faab8fcfd6c415b734295b7c67d2e04ba7b6cfa91a77758af5dda53ae
|
Concept ACK |
|
Closing this as it has not had any activity in a while. If you are interested in continuing work on this, please leave a comment so that it can be reopened. |
Just pass arguments that can't be parsed as JSON as string arguments. If the
RPC method isn't expecting a string argument, this will result in more specific
errors from the RPC. And if it allows an argument to be a string as one
possible type (for example the
hash_or_heightargument togetblockstats),this avoids the need for bitcoin-cli users to use double JSON quoting+shell
quoting to pass the string.