rpc: Logic errors and asserts in rpc code #17181

issue MarcoFalke openend this issue on October 17, 2019
  1. MarcoFalke commented at 8:38 pm on October 17, 2019: member

    Currently, we use assert in RPC code to document logic and code assumptions. However, it seems a bit extreme to abort all of Bitcoin Core on an assert failure in one of the RPC threads. I suggest to replace all checks with a macro THROW_LOGIC_ERROR_IF_ASSERT_FAILS(condition) that does what it says. That logic error will then be returned to the rpc caller and will include instructions to report the error to our issue tracker.

    Any objections or naming suggestions for that macro?

  2. MarcoFalke added the label Brainstorming on Oct 17, 2019
  3. MarcoFalke added the label RPC/REST/ZMQ on Oct 17, 2019
  4. MarcoFalke commented at 8:45 pm on October 17, 2019: member

    There is also a broader proposal to get rid of asserts in non-rpc code:

    • [discussion] Dealing with assertions and optional consistency checking #4576
  5. laanwj commented at 9:18 am on October 18, 2019: member

    I tend to agree. I think assertion errors should be used for critical errors when the sane state of the process can’t be guaranteed anymore. When internal assumptions don’t hold anymore, and when continuing would have a high risk of causing further corruption.

    Then it’s valid to crash.

    For all other cases, please use some form of error handling. In RPC code, we use exceptions for this.

  6. ryanofsky commented at 10:23 am on October 18, 2019: member

    I would encourage more use of std::logic_error instead of asserts. I see logic errors and asserts as semantically equivalent, both indicating the presence of bugs, but logic_errors working better with unit tests. I think the suggested macro could be a good idea, because if (cond) throw std::logic_error(strprintf(...)) is pretty verbose, and I think that discourages use. (Grepping for logic_error` I think every existing logic_error throw actually comes from me and no one other bitcoin developer has written one.)

    However, I don’t think it would be a good idea to ever catch std::logic_error outside of unit tests. I think that defeats the major advantage of logic_errors as logical assertions compatible with having good test coverage.

    If the goal here is better isolation from nonfatal bugs in RPCs, I think I’d suggest instead defining a new NonfatalError class inheriting from std::exception, a CHECK_NONFATAL or similar macro throwing nonfatal error exceptions, and code to catch and handle those exceptions somewhere in the RPC framework.

  7. ryanofsky commented at 10:38 am on October 18, 2019: member
    Going off previous suggestion, CHECK_NONFATAL / NonFatalCheckError might be more consistent naming
  8. MarcoFalke commented at 1:37 pm on October 18, 2019: member
    I don’t understand the rationale for not catching logic_errors from rpc threads and returning them as a verbose string to the caller. We already do that right now. Are you advocating to not catch them and crash? There shouldn’t be any fatal error in rpc code that would warrant a crash. The only case I can think of is a rpc thread calling into validation and running into a database error, but then validation will take care of aborting the whole program.
  9. ryanofsky commented at 2:18 pm on October 18, 2019: member

    Every time I have ever used std::logic_error, I’ve used it to mean that I’ve encountered a bug and I want the program to crash. If I found a bug and don’t want the program to crash, I would use a different exception like std::runtime_error or a custom exception like the suggested CHECK_NONFATAL / NonFatalCheckError. Again, I think the nice thing about logic_error is that it can provide the same semantics as assert without getting in the way of unit test coverage. If we start catching logic_error exceptions then it loses those advantages because I no longer know what to expect when I throw it.

    We already do that right now.

    logic_error doesn’t inherit from runtime_error, so I hope this isn’t the case

    There shouldn’t be any fatal error in rpc code that would warrant a crash

    This is subjective and is something reasonable people can disagree about. But I think it would be best for authors who add checks to clearly distinguish cases where they do and don’t want crashes by using assert or logic_error in fatal cases, and CHECK_NONFATAL or std::runtime_error or similar in nonfatal cases.

    I’m fully onboard with your original suggestion to get rid of asserts in RPC code. All I’m suggesting is that instead of replacing them with logic_error throws, you replace them with something like NonFatalCheckError throws. You already proposed defining a custom THROW_LOGIC_ERROR_IF_ASSERT_FAILS macro, so I don’t see what objection you would have to a shorter, clearer CHECK_NONFATAL macro instead.

  10. ryanofsky commented at 2:39 pm on October 18, 2019: member
    Oops, it turns out we actually do have a lot of code catching std::exception, not std::runtime_error. So maybe std::logic_error is not as useful as I thought it was. I don’t think it’i a good idea to catch std::exception without rethrowing or exiting, but if we’re already doing that, then there are fewer practical consequences to indiscriminately using logic_error for both fatal and nonfatal errors like you are suggesting. I still think it would be better for clarity to use a distinct exception type if you are going out of your way to define a new custom macro. But it does look like our current code is bad enough that using std::logic_error wouldn’t be worse in a practical way right now.
  11. MarcoFalke removed the label Brainstorming on Oct 18, 2019
  12. laanwj closed this on Oct 28, 2019

  13. sidhujag referenced this in commit 6d28260ebf on Oct 28, 2019
  14. sidhujag referenced this in commit a5c20ba4d9 on Nov 10, 2020
  15. MarcoFalke locked this on Dec 16, 2021

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-12-18 21:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me