bitcoin: Inconsistent RPC error handling

Expected behavior

The behavior of returning error from RPC call should be consistent between these cases:

  • Single RPC call fails
  • Single forbidden RPC call
  • Batched failed RPC call
  • One (or more) method of the batched call is forbidden

Actual behavior

  • Single failed RPC call returns HTTP error code
  • Single forbidden RPC call returns HTTP error code - HTTP_FORBIDDEN (403)
  • Batched failed RPC call leaks an internal error code
  • Batched call containing a forbidden method returns HTTP_FORBIDDEN (403) for the whole batch.

To reproduce

Disclaimer: the bug was discovered by code analysis when trying to come up with a correct solution to https://github.com/MetacoSA/NBitcoin/issues/864 I’m fairly confident that using curl to call methods and then observing output would reproduce the issue.

Another way to see a problem might be running BTCPayServer/NBXplorer with the bitcoind version from master with some users restricted. (Example: restrict getpeerinfo and see that Payjoin stops working.) I didn’t try this with newest Core, but I hit it with btc-rpc-proxy, which returns HTTP errors for authentication just like what bitcoind does according to the code.

System information

Not relevant.

Discussion

I’m opening this issue in order to decide on proper handling of RPC errors. I see these possible approaches:

  • RPC_METHOD_NOT_FOUND becomes public, the comment is removed and the rest of the code stays the same, the behavior doesn’t change.
  • JSONErrorReply function is modified to return HTTP errors for batched calls too.
  • New public error codes are defined and used for every method independently, the mapping to HTTP codes is removed (at least for batched calls)

I personally like the last one because it allows efficient inspection of node capabilities, but I’m worried that it might break some clients. I’d love to hear arguments from people who are more experienced in this area.

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Comments: 20 (12 by maintainers)

Commits related to this issue

Most upvoted comments

That should be fine to do. It might be nice to differentiate RPC_METHOD_NOT_FOUND and RPC_METHOD_NOT_ALLOWED. Right now the code does not make a distinction, but you could make RPC_METHOD_NOT_ALLOWED be the error as the precheck, and RPC_METHOD_NOT_FOUND as the one once you try to run it and it’s not there (but may also be nice to make that a pre-checked thing IMO)

https://github.com/bitcoin/bitcoin/pull/12763/files#diff-744201ccb403526a4b5bf52d6e5367deR216-R219

Oh, I thought it was a worse issue than it is! Yes, the code rejects the entire batch if any are not permitted. This is by design; if you have a random failure in the middle of your batch that would be potentially bad. It’s better to reject the whole batch if the user is trying any unpermitted action.

How many RPCs do you actually need to detect? Maybe what I’d suggest is structuring your test-packet as:

Test Packet 1: All Mandatory RPCs Test Packet 2: All Optional RPCs If 2 fails: Test RPCs one-by-one

I don’t have an opinion here sorry for breaking compat. I think that we should change batching to scan if any are not whitelisted and reject the whole batch.