miniscript: convert non-critical asserts to CHECK_NONFATAL #31727

pull darosior wants to merge 1 commits into bitcoin:master from darosior:2501_miniscript_nonfatal changing 2 files +54 −51
  1. darosior commented at 4:17 pm on January 23, 2025: member

    The Miniscript code contains assertions to prevent ending up in an insane state or prevent UB, but also to enforce logical invariants. For the latter it is not necessary to crash the program if they are broken. Raising an exception suffices, especially as this code is often called through the RPC interface which can in turn handle the exception and the user can report it to developers.

    This revives #28678 from Pieter Wuille.

  2. miniscript: convert non-critical asserts to CHECK_NONFATAL
    The Miniscript code contains assertions to prevent ending up in an insane state or prevent UB, but
    also to enforce logical invariants. For the latter it is not necessary to crash the program if they
    are broken. Raising an exception suffices, especially as this code is often called through the RPC
    interface which can in turn handle the exception and the user can report it to developers.
    
    This is based on previous work from Pieter Wuille.
    ff0194a7ce
  3. DrahtBot commented at 4:17 pm on January 23, 2025: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/31727.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK TheCharlatan, brunoerg, hodlinator
    Concept ACK kevkevinpal

    If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #31719 (miniscript: fixes #29098 by only use first k valid signatures by tnndbtc)
    • #31713 (miniscript refactor: Remove unique_ptr-indirection (#30866 follow-up) by hodlinator)

    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.

  4. DrahtBot added the label Descriptors on Jan 23, 2025
  5. brunoerg commented at 4:37 pm on January 23, 2025: contributor
    Concept ACK
  6. in src/script/miniscript.h:662 in ff0194a7ce
    658@@ -659,7 +659,8 @@ struct Node {
    659             stack.pop_back();
    660         }
    661         // The final remaining results element is the root result, return it.
    662-        assert(results.size() == 1);
    663+        assert(results.size() >= 1);
    


    pythcoiner commented at 5:18 pm on January 24, 2025:
    why >= if then you check against == ?

    darosior commented at 7:05 pm on January 24, 2025:
    The assert is a looser check. If this condition doesn’t hold it will trigger UB on the line right after so we’d rather crash. The CHECK_NONFATAL check is stricter and as long as the assert holds only applies to the logic, so it’s not necessary to crash the program. Raising an exception to signal the bug to the user is sufficient.

    maflcko commented at 6:14 pm on February 5, 2025:
    Just for reference, CHECK_NONFATAL is safe (from an UB perspective) to be used as a drop-in replacement for assert/Assert (and vice-versa) with only a slight difference: An assertion failure will abort the whole program, and not continue to the next statement. A nonfatal check failure will also not continue to the next statement, but it will just throw an exception and not fatally abort the whole program.
  7. DrahtBot added the label CI failed on Jan 26, 2025
  8. DrahtBot removed the label CI failed on Jan 26, 2025
  9. darosior commented at 3:33 pm on January 28, 2025: member

    Why aren’t these converted to use CHECK_NONFATAL?

    Same reason as here. I kept asserts where breaking the invariant would lead to UB. In the examples you point out it would read out of the sats vector bounds.

    Actually this should be a strict check, not an inferior or equal to!

  10. hodlinator commented at 1:56 pm on January 29, 2025: contributor

    Same reason as here. I kept asserts where breaking the invariant would lead to UB. In the examples you point out it would read out of the sats vector bounds.

    Okay, and there is no way user input from RPCs etc would currently be able to trigger the asserts?

    Actually this should be a strict check, not an inferior or equal to!

    Ah, didn’t realize, good catch indeed, = should be dropped.

  11. kevkevinpal commented at 3:44 am on February 6, 2025: contributor

    Concept ACK

    lightly reviewed the code and looks good to me

  12. TheCharlatan approved
  13. TheCharlatan commented at 12:51 pm on April 9, 2025: contributor
    ACK ff0194a7ce9dabf1b31b64ca584e45840dce8141
  14. DrahtBot requested review from hodlinator on Apr 9, 2025
  15. DrahtBot requested review from brunoerg on Apr 9, 2025
  16. brunoerg approved
  17. brunoerg commented at 9:20 pm on April 9, 2025: contributor
    code review ACK ff0194a7ce9dabf1b31b64ca584e45840dce8141
  18. hodlinator approved
  19. hodlinator commented at 2:02 pm on April 10, 2025: contributor

    ACK ff0194a7ce9dabf1b31b64ca584e45840dce8141

    Makes sense to not crash when encountering invalid miniscript.

    Testing

    Inserted CHECK_NONFATAL(false) in two separate touched functions to see how RPCs behave:

    0₿ build/bin/bitcoin-cli -regtest deriveaddresses "wsh(1)#mrg7xj7p"
    1error code: -1
    2error message:
    3Internal bug detected: false
    4../src/script/miniscript.cpp:20 (SanitizeType)
    5Bitcoin Core v28.99.0-ff0194a7ce9d-dirty
    6Please report this issue here: https://github.com/bitcoin/bitcoin/issues
    

    Similar for:

    0../src/script/miniscript.cpp:41 (ComputeType)
    

    Following up on my unanswered message:

    Same reason as here. I kept asserts where breaking the invariant would lead to UB. In the examples you point out it would read out of the sats vector bounds.

    Okay, and there is no way user input from RPCs etc would currently be able to trigger the asserts?

    (I acknowledge you drew the line at UB, but out of bounds access fits that definition AFAIK).

    Seems like user input like excessive thresh k-value is guarded against at least to some extent here while string parsing:

    https://github.com/bitcoin/bitcoin/blob/ff0194a7ce9dabf1b31b64ca584e45840dce8141/src/script/miniscript.h#L2125-L2133

    So the asserts referenced in #31727#pullrequestreview-2577746602 will typically run after that guard. Meaning there’s little point in converting those checks to CHECK_NONFATAL.

    Tested:

    0₿ build/bin/bitcoin-cli -regtest deriveaddresses "wsh(thresh(1,pk(tpubDFkN51vYF36W4Yfn3wGv5fpmRo3ok7vZZjc1gmRJjumq33L776e6GkP4HGdCVjDqYiBahXCrXQKja8aUZ2xovQNS8WkF46MdY7TLHJLYD7H/0/0)))#qzdpxsqa"
    1[
    2  "bcrt1q2kwrzducejduqjf36zmx6qzq29l3gc5sca7z2fqcyshm5jr0v4vq7erjda"
    3]
    4
    5₿ build/bin/bitcoin-cli -regtest deriveaddresses "wsh(thresh(2,pk(tpubDFkN51vYF36W4Yfn3wGv5fpmRo3ok7vZZjc1gmRJjumq33L776e6GkP4HGdCVjDqYiBahXCrXQKja8aUZ2xovQNS8WkF46MdY7TLHJLYD7H/0/0)))#zx6ca7mc"
    6error code: -5
    7error message:
    8A function is needed within P2WSH
    

    Not the clearest error message, but at least an error.

    Actually this should be a strict check, not an inferior or equal to!

    Ah, didn’t realize, good catch indeed, = should be dropped.

    Would still be nice if this were addressed, but bug wasn’t caused by this PR, so could be a follow-up.

    Edit: Stroke out inverted logic.

  20. glozow merged this on Apr 10, 2025
  21. glozow closed this on Apr 10, 2025

  22. hodlinator commented at 8:05 am on April 12, 2025: contributor

    @darosior discovered (https://github.com/bitcoin/bitcoin/pull/31727#issuecomment-2619342125) in response to #31727#pullrequestreview-2577746602:

    Ah, didn’t realize, good catch indeed, = should be dropped.

    This is now fixed together with some more cases in follow-up #32255.

  23. darosior commented at 7:46 pm on April 12, 2025: member

    Thanks for picking it up @hodlinator.

    ——– Original Message ——– On 4/12/25 4:06 AM, hodlinator wrote:

    @.***(https://github.com/darosior) discovered (#31727 (comment)) in response to #31727 (review):

    Ah, didn’t realize, good catch indeed, = should be dropped.

    This is now fixed together with some more cases in follow-up #32255.

    — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>

    hodlinator left a comment (bitcoin/bitcoin#31727)

    @.***(https://github.com/darosior) discovered (#31727 (comment)) in response to #31727 (review):

    Ah, didn’t realize, good catch indeed, = should be dropped.

    This is now fixed together with some more cases in follow-up #32255.

    — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>

  24. fanquake referenced this in commit 5116655980 on Apr 14, 2025
  25. darosior deleted the branch on Apr 14, 2025

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: 2025-05-08 21:13 UTC

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