test: Unit tests for taproot/tapscript coverage in interpreter.cpp #25097

pull david-bakin wants to merge 2 commits into bitcoin:master from david-bakin:23279-taproot-unit-tests changing 13 files +2727 −182
  1. david-bakin commented at 4:17 pm on May 9, 2022: contributor

    [Unit tests are not complete to resolve #23279 - yet. But those additional tests - see this space for future developments! - will not change the code presented here.]

    This PR provides unit tests for Taproot functionality in script/interpreter.cpp, #23279.

    Goal is to show correctness vs specifications in BIPs 341/342, and to improve code coverage in Taproot functionality there.

    Intent is to unit test completely without changing interpreter.cpp itself to provide visibility into static functions/private methods. Thus some of the tests must be “indirect”, testing the unit-under-test by probing a visible caller. This makes those specific tests somewhat fragile as they depend on code paths in the caller, which may change in the future. However, such tests are written so they will fail if the unit-under-test isn’t actually called. This is noted in the code of those specific tests.

    No changes to Bitcoin Core are made - just unit tests added. The Boost Test framework file boost/test/execution_monitor.hpp was added to the lint whitelist - this is acceptable because it is a documented public header of the Boost Test framework, which is already part of the project.

    • EvalChecksigTapscript
    • HandleMissingData
    • SignatureHashSchnorr - now with full path coverage
    • GenericTransactionSignatureChecker<T>::VerifySchnorrSignature
    • GenericTransactionSignatureChecker<T>::CheckSchnorrSignature
    • ComputeTaprootMerkleRoot
    • SigVersion::TAPSCRIPT code paths in ExecuteWitnessScript
    • Taproot code paths in VerifyWitnessProgram
    • Tapscript code paths in VerifyWitnessProgram

    TODO: Full Tapscript (BIP-342) unit tests yet to be completed. TODO: Does anything need to be done with libconsensus? Please advise!

    2 commits:

    1. Add new utility functions to src/test/util that are not only used in these tests but may also be useful for future unit tests. Also, refactor some existing utility functions from current tests (mainly, script_tests.cpp) into src/test/util so they can be more widely used too. All of these new test utility functions have unit tests themselves, in src/test/test_utils_tests.cpp.
    2. All the tests for Taproot/Tapscript functionality requested by #23279 in a new file src/test/script_tapscript_tests.cpp. Code coverage runs show 100% coverage of lines and near 100% coverage of branches.

    DEATH TRAP AHEAD!: These unit tests include “death tests” (name comes from Googletest framework): Tests that check that an assert actually fails. These are handled with a Boost execution_monitor (mentioned above) but the asserts still issue messages even when correctly trapped by the Boost Test framework. You’ll see the following in the logs:

     0gitpod /workspace/bitcoin/src/test (23279-taproot-unit-tests) $ ./test_bitcoin 
     1Running 527 test cases...
     2test_bitcoin: script/interpreter.cpp:1495: bool SignatureHashSchnorr(uint256 &, ScriptExecutionData &, const T &, uint32_t, uint8_t, SigVersion, const PrecomputedTransactionData &, MissingDataBehavior) [T = CMutableTransaction]: Assertion `false' failed.
     3test_bitcoin: script/interpreter.cpp:1497: bool SignatureHashSchnorr(uint256 &, ScriptExecutionData &, const T &, uint32_t, uint8_t, SigVersion, const PrecomputedTransactionData &, MissingDataBehavior) [T = CMutableTransaction]: Assertion `in_pos < tx_to.vin.size()' failed.
     4test_bitcoin: script/interpreter.cpp:1528: bool SignatureHashSchnorr(uint256 &, ScriptExecutionData &, const T &, uint32_t, uint8_t, SigVersion, const PrecomputedTransactionData &, MissingDataBehavior) [T = CMutableTransaction]: Assertion `execdata.m_annex_init' failed.
     5test_bitcoin: script/interpreter.cpp:1556: bool SignatureHashSchnorr(uint256 &, ScriptExecutionData &, const T &, uint32_t, uint8_t, SigVersion, const PrecomputedTransactionData &, MissingDataBehavior) [T = CMutableTransaction]: Assertion `execdata.m_tapleaf_hash_init' failed.
     6test_bitcoin: script/interpreter.cpp:1559: bool SignatureHashSchnorr(uint256 &, ScriptExecutionData &, const T &, uint32_t, uint8_t, SigVersion, const PrecomputedTransactionData &, MissingDataBehavior) [T = CMutableTransaction]: Assertion `execdata.m_codeseparator_pos_init' failed.
     7test_bitcoin: script/interpreter.cpp:1469: bool HandleMissingData(MissingDataBehavior): Assertion `!"Missing data"' failed.
     8test_bitcoin: script/interpreter.cpp:1474: bool HandleMissingData(MissingDataBehavior): Assertion `!"Unknown MissingDataBehavior value"' failed.
     9
    10*** No errors detected
    11gitpod /workspace/bitcoin/src/test (23279-taproot-unit-tests) $ 
    

    These specific Assertion ... failed messages are expected. The tests triggering them properly pass iff the assert (and no other) is triggered.


    Coverage results 2022-06-05 showing Taproot coverage (Tapscript tests not yet complete) when only running script_tapscript_tests.cpp:

    EvalChecksigTapscript
    HandleMissingData
    SignatureHashSchnorr
    GenericTransaction-SignatureChecker<T>::CheckSchnorrSignature
    ComputeTaprootMerkleRoot
    VerifyWitnessProgram(Taproot only)
  2. fanquake added the label Tests on May 9, 2022
  3. david-bakin commented at 3:52 am on May 10, 2022: contributor
    (Win64 native [msvc] failed above in functional test feature_index_prune.py - this test has been reported recently as flaky, see #25031.)
  4. david-bakin force-pushed on May 12, 2022
  5. david-bakin renamed this:
    Unit tests for taproot/tapscript coverage in `interpreter.cpp`
    test: Unit tests for taproot/tapscript coverage in `interpreter.cpp`
    on May 14, 2022
  6. david-bakin renamed this:
    test: Unit tests for taproot/tapscript coverage in `interpreter.cpp`
    test: [WIP] Unit tests for taproot/tapscript coverage in `interpreter.cpp`
    on May 14, 2022
  7. david-bakin renamed this:
    test: [WIP] Unit tests for taproot/tapscript coverage in `interpreter.cpp`
    [WIP] test: Unit tests for taproot/tapscript coverage in `interpreter.cpp`
    on May 14, 2022
  8. jonatack commented at 6:47 am on May 18, 2022: contributor

    Squashed and rebased this branch to master and seeing this when running the tests:

    0$  ./src/test/test_bitcoin -t script_tapscript_tests
    1Running 12 test cases...
    2test_bitcoin: script/interpreter.cpp:1495: bool SignatureHashSchnorr(uint256 &, ScriptExecutionData &, const T &, uint32_t, uint8_t, SigVersion, const PrecomputedTransactionData &, MissingDataBehavior) [T = CMutableTransaction]: Assertion `false' failed.
    3test_bitcoin: script/interpreter.cpp:1497: bool SignatureHashSchnorr(uint256 &, ScriptExecutionData &, const T &, uint32_t, uint8_t, SigVersion, const PrecomputedTransactionData &, MissingDataBehavior) [T = CMutableTransaction]: Assertion `in_pos < tx_to.vin.size()' failed.
    4test_bitcoin: script/interpreter.cpp:1528: bool SignatureHashSchnorr(uint256 &, ScriptExecutionData &, const T &, uint32_t, uint8_t, SigVersion, const PrecomputedTransactionData &, MissingDataBehavior) [T = CMutableTransaction]: Assertion `execdata.m_annex_init' failed.
    5test_bitcoin: script/interpreter.cpp:1556: bool SignatureHashSchnorr(uint256 &, ScriptExecutionData &, const T &, uint32_t, uint8_t, SigVersion, const PrecomputedTransactionData &, MissingDataBehavior) [T = CMutableTransaction]: Assertion `execdata.m_tapleaf_hash_init' failed.
    6test_bitcoin: script/interpreter.cpp:1559: bool SignatureHashSchnorr(uint256 &, ScriptExecutionData &, const T &, uint32_t, uint8_t, SigVersion, const PrecomputedTransactionData &, MissingDataBehavior) [T = CMutableTransaction]: Assertion `execdata.m_codeseparator_pos_init' failed.
    7test_bitcoin: script/interpreter.cpp:1469: bool HandleMissingData(MissingDataBehavior): Assertion `!"Missing data"' failed.
    8test_bitcoin: script/interpreter.cpp:1474: bool HandleMissingData(MissingDataBehavior): Assertion `!"Unknown MissingDataBehavior value"' failed.
    
  9. david-bakin commented at 6:50 am on May 18, 2022: contributor

    Squashed and rebased this branch to master and seeing this when running the tests:

    0$  ./src/test/test_bitcoin -t script_tapscript_tests
    1Running 12 test cases...
    2test_bitcoin: script/interpreter.cpp:1495: bool SignatureHashSchnorr(uint256 &, ScriptExecutionData &, const T &, uint32_t, uint8_t, SigVersion, const PrecomputedTransactionData &, MissingDataBehavior) [T = CMutableTransaction]: Assertion `false' failed.
    

    Yes - that’s actually expected. Those are death tests - testing asserts. The Boost Test framework will print that the assertion failed but then it is properly caught with an ExecutionMonitor so the test actually succeeds.

    [Following paragraph was initially wrong but now is correct:] The reason for these tests is that I wanted to get 100% coverage. This routine implements the Schnorr signature hash - which is specified in a BIP and of course is part of the consensus - and it is a very complicated routine - it takes several structs as inputs and those structs can have “optional” fields (but not std::optional) - which may or may not be initialized. I thought it was important to make sure that the logic errors in callers actually caused the asserts to happen. Plus, it makes it easier to look at the coverage report and say, yep, everything in here is tested.

    Do you have any suggestions on how I can improve the documentation or the test to avoid confusion such as this? Perhaps I could use BOOST_TEST_MESSAGE to emit a message: “These following assertions are expected”??

    (There’s a big comment explaining this in the code @1366 but of course people will just see the logs first …)

    P.S. Thank you for checking this PR out! Very encouraging for me…

  10. jonatack commented at 7:04 am on May 18, 2022: contributor
    Oh ok, I hadn’t looked at the code yet (the fixup and merge commits really need to be squashed to encourage people to look at it) but indeed there is a large comment. Agree, logging a message to explain would be helpful.
  11. david-bakin commented at 7:05 am on May 18, 2022: contributor

    I will squash now (actually, in the morning …) - I was waiting until I finished the last couple of tasks but no problem doing it now. Thanks for the tip.

    Also, unfortunately, BOOST_TEST_MESSAGE messages aren’t displayed unless you set a log_level, like --log_level=message - so most people still won’t see it …

  12. jonatack commented at 7:45 am on May 18, 2022: contributor

    I tend to run individual tests with -l test_suite or -l all if anything unusual occurs when running it without a log level.

    In any case, the unit test runner invoked with make check runs it fine locally for me and it looks like you solved your CI issue.

    Edit: nit fixups signaled by test/lint/lint-spelling.py

    0$ test/lint/lint-spelling.py
    1src/test/script_tapscript_tests.cpp:650: tranaction ==> transaction
    2src/test/script_tapscript_tests.cpp:1048: suceeds ==> succeeds
    

    Edit 2: I did see this error with make check, unsure if it was with your latest push:

     0Running tests: from test/script_tapscript_tests.cpp
     1cat: test/script_tapscript_tests.cpp: No such file or directory
     2Missing an argument value for the parameter run_test in the argument 
     3
     4  run_test
     5    Filters which tests to execute.
     6    --run_test=<test unit filter>
     7    -t <test unit filter>
     8
     9
    10  Use
    11      test_bitcoin --help
    12  or  test_bitcoin --help=<parameter name>
    13  for detailed help on Boost.Test parameters.
    14make[3]: *** [Makefile:20940: test/script_tapscript_tests.cpp.test] Error 1
    15make[3]: *** Waiting for unfinished jobs....
    
  13. in src/test/script_tapscript_tests.cpp:602 in a5808ce2f0 outdated
    597+                                  * hash_type_input_alternatives.size()
    598+                                  * annex_alternatives.size()
    599+                                  * output_hash_alternatives.size()
    600+                                  - 8 /* exclude SIGHASH_DEFAULT w/ SISHASH_ANYONECANPAY */;
    601+
    602+        BOOST_TEST_MESSAGE("Running " << nAlternatives << "scenarios");
    


    jonatack commented at 7:46 am on May 18, 2022:

    Noticed this in the test output.

    0        BOOST_TEST_MESSAGE("Running " << nAlternatives << " scenarios");
    

    david-bakin commented at 8:16 pm on May 19, 2022:
    Fixed.
  14. in src/test/script_tapscript_tests.cpp:163 in a5808ce2f0 outdated
    158+
    159+        bool CheckSchnorrSignature(Span<const unsigned char> sig,
    160+                                    Span<const unsigned char> pubkey,
    161+                                    SigVersion sigversion,
    162+                                    ScriptExecutionData& execdata,
    163+                                    ScriptError* serror = nullptr) const override
    


    jamesob commented at 3:33 pm on May 18, 2022:
    At some point (maybe before this exits draft state) you might want to run clang format on this whole file.

    david-bakin commented at 8:17 pm on May 19, 2022:
    OK!
  15. in src/test/script_tapscript_tests.cpp:1201 in a5808ce2f0 outdated
    1196+            BOOST_TEST((!from_hex(std::string{1, dig} + dig)));
    1197+        }
    1198+    }
    1199+
    1200+    // hex strings to byte vector
    1201+    BOOST_TEST("0A"_hex == valtype(1, 0x0a));
    


    jamesob commented at 4:33 pm on May 18, 2022:

    Wow, TIL about user-defined literals in C++11.

    So these are cool, but is the “xx”_hex stuff actually used in taproot-specific tests anywhere here? I can’t find any usages, which would make that facility (and these tests) unnecessary if I’m reading right.


    david-bakin commented at 8:18 pm on May 19, 2022:
    I’m going to move all of these helpers off into homes in src/test/util where they can be used to make unit tests easier to write/read/maintain. But reduce the set of them at the same time - there’s some redundancy, as you’ve noticed. (In a subsequent push to this PR.)

    david-bakin commented at 5:00 am on May 21, 2022:
    And that’s done now.
  16. jamesob commented at 4:38 pm on May 18, 2022: member

    Concept ACK

    Nice job so far! These tests are well formulated. I like how declarative and readable they are. I’ll review more of the substance once this exits draft state.

  17. david-bakin commented at 8:16 pm on May 19, 2022: contributor

    Edit: nit fixups signaled by test/lint/lint-spelling.py

    Fixed, and I’ll run lint-spelling on my own from now on.

    Edit 2: I did see this error with make check, unsure if it was with your latest push:

    0Running tests: from test/script_tapscript_tests.cpp
    1cat: test/script_tapscript_tests.cpp: No such file or directory
    2Missing an argument value for the parameter run_test in the argument 
    3
    4  run_test
    5...
    

    I do not see this when running make check or when running test_bitcoin either with or without --run_test=script_tapscript_tests. Relevant section of my terminal spew when running make check locally:

    0...
    1Running tests: script_tapscript_tests from test/script_tapscript_tests.cpp
    2export TEST_LOGFILE=/workspace/bitcoin/src/$( echo test/script_tapscript_tests.cpp | grep -E -o "(wallet/test/.*\.cpp|test/.*\.cpp)" | /usr/bin/sed -e s/\.cpp/.log/ ) && \
    3test/test_bitcoin --catch_system_errors=no -l test_suite -t "$( cat test/script_tapscript_tests.cpp | grep -E "(BOOST_FIXTURE_TEST_SUITE\\(|BOOST_AUTO_TEST_SUITE\\()" | cut -d '(' -f 2 | cut -d ',' -f 1 | cut -d ')' -f 1 )" -- DEBUG_LOG_OUT > "$TEST_LOGFILE" 2>&1 || (cat "$TEST_LOGFILE" && false)
    4Running tests: script_tests from test/script_tests.cpp
    5...
    

    And the CI checks all pass too. Not sure how to proceed on this report.

  18. david-bakin force-pushed on May 21, 2022
  19. david-bakin commented at 4:31 am on May 21, 2022: contributor

    Squashed now as requested. Still 2 tests left to write: They’re tough ones as both are for static free functions well hidden by an accessible public free function, and no easy hooks like polymorphic classes to mock/fake to get in there with.

    However, all general-purpose “test only” internal helpers - data structures, functions for visibility, etc. - are now in src/test/util headers, with tests for them in src/test/test_util_tests.cpp.

  20. DrahtBot commented at 1:48 pm on May 24, 2022: contributor

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

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #25648 (refactor: Remove all policy globals by MarcoFalke)
    • #25325 (Add pool based memory resource by martinus)
    • #22954 ([TESTS] Allow tx_invalid.json tests to include flag rules for if_unset: [A,B,C] then_unset: [D] by JeremyRubin)
    • #22876 ([TESTS] Update Transaction Tests to permit setting a flag as always on and disabling the exhaustive failure test by JeremyRubin)
    • #22793 (Simplify BaseSignatureChecker virtual functions and GenericTransactionSignatureChecker constructors by achow101)
    • #22338 ([Refactor]: Rename Script methods that only work on PreTapScript scripts by sanket1729)
    • #20100 (Script: split policy/error consensus codes for CLEANSTACK, MINIMALIF by sanket1729)

    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.

  21. david-bakin commented at 5:50 pm on May 24, 2022: contributor

    DrahtBot said:

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #25152 (refactor: Split util/system into exception, shell, and fs-specific files by Empact)

    Referenced PR is a refactoring PR. I tried it out in my branch. Only merge conflict here is to src/Makefile.test.include (and it’s not a “real” conflict: just two lines changed, one in each PR, which happen to be adjacent (due to the alphabet)) which will be easily merged whichever PR lands first.

  22. david-bakin force-pushed on May 24, 2022
  23. laanwj referenced this in commit cacbdbaa95 on May 26, 2022
  24. sidhujag referenced this in commit 85b89f3426 on May 28, 2022
  25. Add new test utility methods; break out some existing ones
    - Add new test utility methods for use in various unit tests.
    - Refactor some existing methods out of tests where they're currently
      embedded into the test util area.
    - Ensure that the conversions of string name to/from ScriptError_t have
      all the defined enum values.
    - And provide unit tests for the whole shebang.
    12ae33708e
  26. Unit tests for Tap{root,script} of `interpreter.cpp`, #23279
    This commit provides unit tests for Taproot functionality in
    `script/interpreter.cpp`, #23279.
    
    Goal is to show correctness vs specifications in BIPs 341/342, and to
    improve code coverage in Taproot functionality there.
    
    Intent is to unit test completely without changing `interpreter.cpp`
    itself to provide visibility into static functions/private methods.
    Thus some of the tests must be "indirect", testing the unit-under-test
    by probing a visible caller. This makes those specific somewhat fragile
    as they depend on code paths in the caller, which may change in the
    future.  However, such tests are written so they will fail if the
    unit-under-test isn't actually called. This is noted in the code of
    those specific tests.
    
    No changes to Bitcoin Core are made - just unit tests added. The
    Boost Test framework file `boost/test/execution_monitor.hpp` was
    added to the lint whitelist - this is acceptable because it is a
    documented public header of the Boost Test framework, which is
    already part of the project.
    
    - [x] `EvalChecksigTapscript`
    - [x] `HandleMissingData`
    - [x] `SignatureHashSchnorr` - now with full _path_ coverage
    - [x] `GenericTransactionSignatureChecker<T>::VerifySchnorrSignature`
    - [x] `GenericTransactionSignatureChecker<T>::CheckSchnorrSignature`
    - [x] `ComputeTaprootMerkleRoot`
    - [ ] `SigVersion::TAPSCRIPT` code paths in `ExecuteWitnessScript`
    - [x] Taproot code paths in `VerifyWitnessProgram`
    - [ ] Tapscript code paths in `VerifyWitnessProgram`
    
    **TODO:** Full Tapscript (BIP-342) unit tests yet to be completed.
    **TODO:** Does anything need to be done with `libconsensus`? Please advise!
    
    **N.B.:** These unit tests include "death tests" (name comes from
    Googletest framework): Tests that check that an `assert` actually
    fails.  These are handled with a Boost `execution_monitor`
    (mentioned above) but the asserts _still issue messages_ even when
    by correctly trapped by the Boost Test framework.  You'll see the following:
    
    ```
    gitpod /workspace/bitcoin/src/test (23279-taproot-unit-tests) $ ./test_bitcoin
    Running 527 test cases...
    test_bitcoin: script/interpreter.cpp:1495: bool SignatureHashSchnorr(uint256 &, ScriptExecutionData &, const T &, uint32_t, uint8_t, SigVersion, const PrecomputedTransactionData &, MissingDataBehavior) [T = CMutableTransaction]: Assertion `false' failed.
    test_bitcoin: script/interpreter.cpp:1497: bool SignatureHashSchnorr(uint256 &, ScriptExecutionData &, const T &, uint32_t, uint8_t, SigVersion, const PrecomputedTransactionData &, MissingDataBehavior) [T = CMutableTransaction]: Assertion `in_pos < tx_to.vin.size()' failed.
    test_bitcoin: script/interpreter.cpp:1528: bool SignatureHashSchnorr(uint256 &, ScriptExecutionData &, const T &, uint32_t, uint8_t, SigVersion, const PrecomputedTransactionData &, MissingDataBehavior) [T = CMutableTransaction]: Assertion `execdata.m_annex_init' failed.
    test_bitcoin: script/interpreter.cpp:1556: bool SignatureHashSchnorr(uint256 &, ScriptExecutionData &, const T &, uint32_t, uint8_t, SigVersion, const PrecomputedTransactionData &, MissingDataBehavior) [T = CMutableTransaction]: Assertion `execdata.m_tapleaf_hash_init' failed.
    test_bitcoin: script/interpreter.cpp:1559: bool SignatureHashSchnorr(uint256 &, ScriptExecutionData &, const T &, uint32_t, uint8_t, SigVersion, const PrecomputedTransactionData &, MissingDataBehavior) [T = CMutableTransaction]: Assertion `execdata.m_codeseparator_pos_init' failed.
    test_bitcoin: script/interpreter.cpp:1469: bool HandleMissingData(MissingDataBehavior): Assertion `!"Missing data"' failed.
    test_bitcoin: script/interpreter.cpp:1474: bool HandleMissingData(MissingDataBehavior): Assertion `!"Unknown MissingDataBehavior value"' failed.
    
    *** No errors detected
    gitpod /workspace/bitcoin/src/test (23279-taproot-unit-tests) $
    ```
    
    These specific `Assertion ... failed` messages are _expected_.  The
    tests triggering them properly _pass_ iff the `assert` (and no other)
    is _triggered_.
    eeefec3435
  27. david-bakin force-pushed on Jun 5, 2022
  28. david-bakin renamed this:
    [WIP] test: Unit tests for taproot/tapscript coverage in `interpreter.cpp`
    test: Unit tests for taproot/tapscript coverage in `interpreter.cpp`
    on Jun 5, 2022
  29. david-bakin marked this as ready for review on Jun 5, 2022
  30. david-bakin commented at 4:50 am on June 6, 2022: contributor

    DrahtBot said:

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #22793 (Simplify BaseSignatureChecker virtual functions and GenericTransactionSignatureChecker constructors by achow101)

    Referenced PR updates BaseSignatureChecker and GenericSignatureChecker which are used in these tests, and also various the internals of some routines in interpreter.cpp including CheckSchnorrSignature.

    Most of the resulting conflicts are easy to resolve; the tricky one was the update to CheckSchnorrSignature which changed its behavior in such a way that one of these tests became invalid.

    • This was exactly the case I was referring to in the PR header comment when I said:

      This makes those specific tests somewhat fragile as they depend on code paths in the caller, which may change in the future. However, such tests are written so they will fail if the unit-under-test isn’t actually called. This is noted in the code of those specific tests.

      And naturally it was immediately hit! But it was also easily fixable.

    So in fact I am ready to update this PR if #22793 lands first. And also, except for that, I can update this code now so that there won’t be any conflict if #22793 lands later.

    (I am of the opinion that there are routines in interpreter.cpp which are defined there static which needn’t be. They could just be file-scoped. And thus these unit tests could call them directly (by providing the prototype) and test them directly rather than having to go indirectly through CheckSchnorrSignature, and so on. But I didn’t want to change interpreter.cpp to add unit tests after-the-fact. I thought it would make it easier to get approvals for this PR if I didn’t make changes there.)

  31. in src/test/util/pretty_data.cpp:176 in eeefec3435
    172+std::optional<ScriptError_t> ParseScriptError(std::string_view name)
    173 {
    174     for (const auto& se : script_errors)
    175         if (se.name == name)
    176             return se.err;
    177-    if (issue_boost_error) BOOST_ERROR("Unknown scripterror \"" << name << "\" in test description");
    


    jamesob commented at 8:58 pm on July 8, 2022:

    https://github.com/bitcoin/bitcoin/pull/25097/commits/eeefec343592c6de85048e3b055ba49755cfb072

    You may want to move these BOOST_ERROR(...) changes back to the previous commit (where this file is introduced), since attempting to build the previous commit fails with this error:

     0/usr/bin/ld: /usr/bin/ld: DWARF error: could not find variable specification at offset 7218
     1libtest_util.a(libtest_util_a-pretty_data.o): in function `ParseScriptFlags(std::basic_string_view<char, std::char_traits<char> >, bool)':
     2./src/test/util/pretty_data.cpp:138: undefined reference to `boost::unit_test::unit_test_log_t::set_checkpoint(boost::unit_test::basic_cstring<char const>, unsigned long, boost::unit_test::basic_cstring<char const>)'
     3/usr/bin/ld: libtest_util.a(libtest_util_a-pretty_data.o): in function `lazy_ostream_impl':
     4/usr/include/boost/test/utils/lazy_ostream.hpp:74: undefined reference to `boost::unit_test::lazy_ostream::inst'
     5/usr/bin/ld: libtest_util.a(libtest_util_a-pretty_data.o): in function `ParseScriptFlags(std::basic_string_view<char, std::char_traits<char> >, bool)':
     6./src/test/util/pretty_data.cpp:138: undefined reference to `boost::test_tools::tt_detail::report_assertion(boost::test_tools::assertion_result const&, boost::unit_test::lazy_ostream const&, boost::unit_test::basic_cstring<char const>, unsigned long, boost::test_tools::tt_detail::tool_level, boost::test_tools::tt_detail::check_type, unsigned long, ...)'
     7/usr/bin/ld: libtest_util.a(libtest_util_a-pretty_data.o): in function `FormatScriptError[abi:cxx11](ScriptError_t, bool)':
     8./src/test/util/pretty_data.cpp:167: undefined reference to `boost::unit_test::unit_test_log_t::set_checkpoint(boost::unit_test::basic_cstring<char const>, unsigned long, boost::unit_test::basic_cstring<char const>)'
     9/usr/bin/ld: libtest_util.a(libtest_util_a-pretty_data.o): in function `lazy_ostream_impl':
    10/usr/include/boost/test/utils/lazy_ostream.hpp:74: undefined reference to `boost::unit_test::lazy_ostream::inst'
    11/usr/bin/ld: libtest_util.a(libtest_util_a-pretty_data.o): in function `FormatScriptError[abi:cxx11](ScriptError_t, bool)':
    12./src/test/util/pretty_data.cpp:167: undefined reference to `boost::test_tools::tt_detail::report_assertion(boost::test_tools::assertion_result const&, boost::unit_test::lazy_ostream const&, boost::unit_test::basic_cstring<char const>, unsigned long, boost::test_tools::tt_detail::tool_level, boost::test_tools::tt_detail::check_type, unsigned long, ...)'
    13/usr/bin/ld: libtest_util.a(libtest_util_a-pretty_data.o): in function `ParseScriptError(std::basic_string_view<char, std::char_traits<char> >, bool)':
    14./src/test/util/pretty_data.cpp:176: undefined reference to `boost::unit_test::unit_test_log_t::set_checkpoint(boost::unit_test::basic_cstring<char const>, unsigned long, boost::unit_test::basic_cstring<char const>)'
    15/usr/bin/ld: libtest_util.a(libtest_util_a-pretty_data.o): in function `lazy_ostream_impl':
    16/usr/include/boost/test/utils/lazy_ostream.hpp:74: undefined reference to `boost::unit_test::lazy_ostream::inst'
    17/usr/bin/ld: libtest_util.a(libtest_util_a-pretty_data.o): in function `ParseScriptError(std::basic_string_view<char, std::char_traits<char> >, bool)':
    18./src/test/util/pretty_data.cpp:176: undefined reference to `boost::test_tools::tt_detail::report_assertion(boost::test_tools::assertion_result const&, boost::unit_test::lazy_ostream const&, boost::unit_test::basic_cstring<char const>, unsigned long, boost::test_tools::tt_detail::tool_level, boost::test_tools::tt_detail::check_type, unsigned long, ...)'
    19/usr/bin/ld: libtest_util.a(libtest_util_a-pretty_data.o): in function `_GLOBAL__sub_I_pretty_data.cpp':
    20/usr/include/boost/test/unit_test_log.hpp:227: undefined reference to `boost::unit_test::unit_test_log_t::instance()'
    21clang: error: linker command failed with exit code 1 (use -v to see invocation)
    
  32. in src/test/test_util_tests.cpp:235 in 12ae33708e outdated
    230+    }
    231+}
    232+
    233+#define EVAL(...) []() -> bool { return __VA_ARGS__; }()
    234+
    235+BOOST_AUTO_TEST_CASE(is_base_of_trait)
    


    jamesob commented at 9:15 pm on July 8, 2022:

    https://github.com/bitcoin/bitcoin/pull/25097/commits/12ae33708ee1978e2a215954e41e6ccf4f0a25fd

    Is there a reason to include this test case? This doesn’t look like it’s testing any non-std functionality. It also seems like a direct adaptation of the example usage here: https://en.cppreference.com/w/cpp/types/is_base_of

  33. jamesob commented at 9:37 pm on July 8, 2022: member

    Partial review done

    Code is high quality so far (if not a little complex), and I really like the look of these tests. Will finish review early next week, probably Monday.


    • 12ae33708e Add new test utility methods; break out some existing ones

    A lot of this code is fairly elaborate in terms of use of C++ templating features - for example, all the machinations necessary to get Hex() to work - which I think I’d be hesitant to include in non-test code. But since these are tests, the complexity/convenience trade-off seems okay.

    • eeefec3435 Unit tests for Tap{root,script} of interpreter.cpp, #23279
  34. david-bakin commented at 2:41 pm on July 11, 2022: contributor

    Partial review done

    Addressing these comments now.

    Code is high quality so far (if not a little complex), and I really like the look of these tests. Will finish review early next week, probably Monday.

    Thank you, and looking forward to more comments!

    Is it preferred (i.e., do you prefer) squashing during a review or should I fix things in an additional commit on top of this one while you’re in progress and squash it later?

  35. jamesob commented at 1:39 pm on July 12, 2022: member

    Is it preferred (i.e., do you prefer) squashing during a review or should I fix things in an additional commit on top of this one while you’re in progress and squash it later?

    Typically squashes are done immediately because if you squash at some point later, all reviewers will have to re-review to ensure that the code hasn’t actually changed unexpectedly during the squash.

  36. in src/test/script_tapscript_tests.cpp:893 in eeefec3435
    888+        uint256 m_expected_sighash = []() {
    889+            uint256 h{};
    890+            // This is the known sighash of the Tx and input data we set up (precomputed)
    891+            h.SetHex("f614d8ae6dcc49e2ca2ef1c03f93c7326189e5575d446e825e5a2700fb1cb83c");
    892+            return h;
    893+        }();
    


  37. in src/test/script_tapscript_tests.cpp:899 in eeefec3435
    894+
    895+        using MutableTransactionSignatureChecker::MutableTransactionSignatureChecker;
    896+
    897+        enum class if_as_expected_return { False,
    898+                                           True };
    899+        if_as_expected_return m_iae{if_as_expected_return::True};
    


    jamesob commented at 7:00 pm on July 12, 2022:
  38. in src/test/script_tapscript_tests.cpp:947 in eeefec3435
    942+            BOOST_TEST(!sut.CheckSchnorrSignature(testsig, triplet.m_pubkey, SigVersion::TAPROOT, execdata, &serror));
    943+            BOOST_TEST(serror == SCRIPT_ERR_SCHNORR_SIG_HASHTYPE);
    944+        }
    945+        {
    946+            // Negative tests: last byte is _not_ SIGHASH_DEFAULT, but we early exit _without changing
    947+            // serror_ because we don't provide a txDataIn (🡄 this requires knowledge of how
    


  39. in src/test/script_tapscript_tests.cpp:961 in eeefec3435
    956+            }
    957+        }
    958+    }
    959+
    960+    {
    961+        // Now check that, given the parameters, if `SignatureHashSchnorr fails there's an error exit.
    


  40. in src/test/script_tapscript_tests.cpp:1280 in eeefec3435
    1275+
    1276+        Context& SetValidSignatureInWitness(unsigned char hash_type = SIGHASH_DEFAULT)
    1277+        {
    1278+            m_hash_type = hash_type;
    1279+            m_witness_signature = m_sig;
    1280+            if (hash_type) m_witness_signature.push_back(hash_type);
    


    jamesob commented at 7:42 pm on July 12, 2022:

    https://github.com/bitcoin/bitcoin/pull/25097/commits/eeefec343592c6de85048e3b055ba49755cfb072

    If you wind up having to retouch this commit, I might advise changing if (hash_type) to if (hash_type != SIGHASH_DEFAULT) here and below; to me it’s a little clearer and less tricky… I had to verify that SIGHASH_DEFAULT would evaluate to false in this context.

  41. in src/test/script_tapscript_tests.cpp:1400 in eeefec3435
    1395+            SignatureCheckerMock checker_mock(m_checker_validation);
    1396+            CScript script_sig; // must be empty for actual Taproot
    1397+            if (m_p2sh_wrapped) {
    1398+                // But BIP-341 allows all SegWit v1 P2SH-wrapped outputs to pass
    1399+                valtype fake_hash(20, 0x00);
    1400+                script_sig << OP_0 << fake_hash;
    


    jamesob commented at 8:00 pm on July 12, 2022:

    https://github.com/bitcoin/bitcoin/pull/25097/commits/eeefec343592c6de85048e3b055ba49755cfb072

    Interesting… if I change this to OP_1 or remove the OP_0 << altogether, all tests still pass.

  42. in src/test/script_tapscript_tests.cpp:1438 in eeefec3435
    1433+        }
    1434+
    1435+        Context& CheckSignatureCheckerWasCalled()
    1436+        {
    1437+            BOOST_CHECK_MESSAGE(m_checker_was_called,
    1438+                                Descr() << ": Schnoor signature checker was called, as expected");
    


    jamesob commented at 8:01 pm on July 12, 2022:
  43. jamesob commented at 8:25 pm on July 12, 2022: member

    approach ACK eeefec343592c6de85048e3b055ba49755cfb072 (jamesob/ackr/25097.1.david-bakin.test_unit_tests_for_tapr)

    Wow, thanks for this contribution @david-bakin. These are some really fine-grained tests for various Taproot related parts of the script interpreter. The code here is very readable and seems nicely extensible. Clearly a lot of work went into this.

    For many parts of the codebase, this sort of testing would be overkill IMO because it is so tightly coupled to the tested code. But in the case of script interpretation - debatably the heart of bitcoin validation - I think it’s worthwhile to have painstakingly involved tests at the cost of slight maintenance burden if the underlying code happens to change somehow. Maybe someone more experienced than me w.r.t. changing the script interpreter can weigh in here and confirm my intuition.

    All of my comments are pretty minor. I’d say it might be wortwhile to break out the Parse*() optional changes in the second commit either into their own commit, or as I mentioned in a previous review, fold it into the first.

  44. DrahtBot commented at 9:24 am on August 3, 2022: contributor

    🐙 This pull request conflicts with the target branch and needs rebase.

    Want to unsubscribe from rebase notifications on this pull request? Just convert this pull request to a “draft”.

  45. DrahtBot added the label Needs rebase on Aug 3, 2022
  46. achow101 commented at 7:20 pm on October 12, 2022: member
    Are you still working on this?
  47. david-bakin commented at 8:00 pm on October 12, 2022: contributor

    yes sorry - i will update by tomorrow!

    On Wed, Oct 12, 2022 at 12:21 PM Andrew Chow @.***> wrote:

    Are you still working on this?

    — Reply to this email directly, view it on GitHub https://github.com/bitcoin/bitcoin/pull/25097#issuecomment-1276634618, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA7YLBE6IOKK4MJDCZ47JYDWC4FUPANCNFSM5VOZLXLQ . You are receiving this because you were mentioned.Message ID: @.***>

  48. achow101 commented at 5:16 pm on November 10, 2022: member

    yes sorry - i will update by tomorrow!

    It’s been several weeks since this comment with no additional updates, so I’m going to close this for now. If you do get around to working on this, please leave a comment so that it can be reopened.

  49. achow101 closed this on Nov 10, 2022

  50. jamesob commented at 8:12 pm on November 10, 2022: member
    Sad to see this closed as it contains some novel unittest coverage. Please feel free to reopen with updates @david-bakin. Hopefully others will step in to review as well.
  51. david-bakin commented at 9:27 pm on November 10, 2022: contributor

    Soon! Tied up temporarily

    On Thu, Nov 10, 2022, 12:12 jamesob @.***> wrote:

    Sad to see this closed as it contains some novel unittest coverage. Please feel free to reopen with updates @david-bakin https://github.com/david-bakin. Hopefully others will step in to review as well.

    — Reply to this email directly, view it on GitHub https://github.com/bitcoin/bitcoin/pull/25097#issuecomment-1310840025, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA7YLBHXF2WHJN3HJ2HN4E3WHVJKNANCNFSM5VOZLXLQ . You are receiving this because you were mentioned.Message ID: @.***>

  52. bitcoin locked this on Nov 10, 2023

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-11-21 15:12 UTC

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