qa: Make wallet_multiwallet.py Windows crossbuild-compatible #34418

pull hodlinator wants to merge 10 commits into bitcoin:master from hodlinator:2026/01/31409_fix changing 3 files +200 −138
  1. hodlinator commented at 12:35 PM on January 27, 2026: contributor

    Makes the functional test compatible with Linux->Windows cross-built executables.

    Main parts:

    • Commit "qa: Check for platform-independent part of error message" switches to match on platform-independent part of error message.
    • Commit "qa: Test scanning errors individually" disentangles code causing the same error message substring, based on #31410.
    • Commit "qa: Disable parts of the test when running under Windows or root" enables the test to be run on Windows, based in part on #31410 (comment).

    Also:

    • Removes unused option in wallet_multiwallet.py.
    • Breaks apart wallet_multiwallet.py's run_test() into smaller test functions.
    • Improves assert_equal() output for dicts.

    Fixes #31409.

  2. DrahtBot added the label Tests on Jan 27, 2026
  3. DrahtBot commented at 12:35 PM on January 27, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

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

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

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

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK janb84, w0xlt, achow101
    Concept ACK hebasto

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #34603 (wallet: Fix detection of symlinks on Windows by achow101)
    • #34544 (wallet: Disallow wallet names that are paths including .. and . elements by achow101)
    • #34439 (qa: Drop recursive deletes from test code, add lint checks. by davidgumberg)
    • #33186 (wallet, test: Ancient Wallet Migration from v0.14.3 (no-HD and Single Chain) by w0xlt)

    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.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  4. hodlinator renamed this:
    qa: Make `wallet_multiwallet.py` Windows-compatible
    qa: Make wallet_multiwallet.py Windows-compatible
    on Jan 27, 2026
  5. hebasto commented at 3:29 PM on January 27, 2026: member

    Concept ACK.

    Thanks for taking this over!

  6. w0xlt commented at 10:22 PM on January 27, 2026: contributor

    Approach ACK. I’ll review it more closely soon.

  7. in test/functional/test_framework/util.py:81 in 596752a06d outdated
      74 | @@ -75,7 +75,10 @@ def summarise_dict_differences(thing1, thing2):
      75 |  def assert_equal(thing1, thing2, *args):
      76 |      if thing1 != thing2 and not args and isinstance(thing1, dict) and isinstance(thing2, dict):
      77 |          d1,d2 = summarise_dict_differences(thing1, thing2)
      78 | -        raise AssertionError("not(%s == %s)\n  in particular not(%s == %s)" % (thing1, thing2, d1, d2))
      79 | +        if d1 != thing1 or d2 != thing2:
      80 | +            raise AssertionError(f"not({thing1!s} == {thing2!s})\n  in particular not({d1!s} == {d2!s})")
      81 | +        else:
      82 | +            raise AssertionError(f"not({thing1!s} == {thing2!s})")
    


    janb84 commented at 4:49 PM on February 3, 2026:

    Given the test on line 76 , we only enter if thing1 and thing2 are not equal. And and summarise_dict_differences filters to show only differences, we'll always have either d1 != thing1 or d2 != thing2 or both !=

    What am I missing so that we hit the else case (L80-81)?


    hodlinator commented at 8:48 AM on February 5, 2026:

    Say you have:

    thing1 = {"name": "Alice", "age": 30}
    thing2 = {}
    

    summarise_dict_differences() will not boil away any similarities between the two, so we'll end up with:

    d1 = {"name": "Alice", "age": 30}
    d2 = {}
    

    so master would print the same values twice, but there's no need to have the "in particular" part.


    This however:

    thing1 = {"name": "Alice", "age": 30}
    thing2 = {"name": "Alice"}
    

    would hopefully result in:

    d1 = {"age": 30}
    d2 = {}
    

    so we would want the "in particular" part.


    janb84 commented at 9:22 AM on February 5, 2026:

    I'm sorry, I missed the {} collection option. Thanks for the explanation.

  8. janb84 commented at 10:46 AM on February 6, 2026: contributor

    <!--meta-tag:bot-skip-->

    ~ACK 596752a06d530918fafc84110195a7067835e949~

    EDIT: I made the wrong judgement on the difference in loggin (seeing more tests) as enough proof that the PR is an improvement next to an code-review. Will re-vist this PR.

    This PR makes wallet_multiwallet.py Windows-compatible. Tested it on windows 11, msvc build (vs 2022)

    <details><summary>this PR</summary>

    2026-02-06T10:25:48.016394Z TestFramework (INFO): PRNG seed is: 3924437959039469419
    2026-02-06T10:25:48.049997Z TestFramework (INFO): Initializing test directory C:\Users\user\AppData\Local\Temp\bitcoin_func_test_nylizqfb
    2026-02-06T10:25:48.550233Z TestFramework (WARNING): Skipping chmod+symlink checks on Windows: chmod works differently due to how access rights work and symlink behavior with regard to the standard library is non-standard on cross-built binaries.
    2026-02-06T10:25:48.756512Z TestFramework (INFO): Test mixed wallets
    2026-02-06T10:25:49.850237Z TestFramework (INFO): Test initialization
    2026-02-06T10:25:52.819255Z TestFramework (INFO): Test balances and fees
    2026-02-06T10:25:54.266821Z TestFramework (INFO): Check for per-wallet settxfee call
    2026-02-06T10:25:54.270096Z TestFramework (INFO): Test dynamic wallet loading
    2026-02-06T10:25:54.748885Z TestFramework (INFO): Load first wallet
    2026-02-06T10:25:54.760269Z TestFramework (INFO): Load second wallet
    2026-02-06T10:25:54.769925Z TestFramework (INFO): Concurrent wallet loading
    2026-02-06T10:25:54.803331Z TestFramework (INFO): Load remaining wallets
    2026-02-06T10:25:54.856230Z TestFramework (INFO): Test dynamic wallet creation
    2026-02-06T10:25:54.929120Z TestFramework (INFO): Test dynamic wallet unloading
    2026-02-06T10:25:56.604190Z TestFramework (INFO): Test wallet backup and restore
    2026-02-06T10:25:57.908829Z TestFramework (INFO): Test wallet lock file is closed
    2026-02-06T10:25:58.309178Z TestFramework (INFO): Stopping nodes
    2026-02-06T10:25:58.464283Z TestFramework (INFO): Cleaning up C:\Users\user\AppData\Local\Temp\bitcoin_func_test_nylizqfb on exit
    2026-02-06T10:25:58.464577Z TestFramework (INFO): Tests successful
    

    </details>

    <details><summary> Master </summary>

    2026-02-06T10:44:32.520149Z TestFramework (INFO): PRNG seed is: 9079423242423824445
    2026-02-06T10:44:32.557824Z TestFramework (INFO): Initializing test directory C:\Users\user\AppData\Local\Temp\bitcoin_func_test_3ac39i27
    2026-02-06T10:44:33.134825Z TestFramework (INFO): Verify warning is emitted when failing to scan the wallets directory
    2026-02-06T10:44:33.135065Z TestFramework (WARNING): Skipping test involving chmod as Windows does not support it.
    2026-02-06T10:44:38.490235Z TestFramework (INFO): Check for per-wallet settxfee call
    2026-02-06T10:44:38.492665Z TestFramework (INFO): Test dynamic wallet loading
    2026-02-06T10:44:38.978126Z TestFramework (INFO): Load first wallet
    2026-02-06T10:44:38.990162Z TestFramework (INFO): Load second wallet
    2026-02-06T10:44:38.999576Z TestFramework (INFO): Concurrent wallet loading
    2026-02-06T10:44:39.036463Z TestFramework (INFO): Load remaining wallets
    2026-02-06T10:44:39.087449Z TestFramework (INFO): Test dynamic wallet creation.
    2026-02-06T10:44:39.150340Z TestFramework (INFO): Test dynamic wallet unloading
    2026-02-06T10:44:40.821876Z TestFramework (INFO): Test wallet backup
    2026-02-06T10:44:42.673883Z TestFramework (INFO): Stopping nodes
    2026-02-06T10:44:42.828266Z TestFramework (INFO): Cleaning up C:\Users\user\AppData\Local\Temp\bitcoin_func_test_3ac39i27 on exit
    2026-02-06T10:44:42.828464Z TestFramework (INFO): Tests successful
    

    </details>

    Test also still works on nix-shell/aarch64

  9. DrahtBot requested review from hebasto on Feb 6, 2026
  10. DrahtBot requested review from w0xlt on Feb 6, 2026
  11. in test/functional/wallet_multiwallet.py:76 in 596752a06d outdated
      82 | +        self.check_chmod = True
      83 | +        self.check_symlinks = True
      84 | +        if platform.system() == 'Windows':
      85 | +            # Additional context:
      86 | +            # - chmod: Posix has one user per file while Windows has an ACL approach
      87 | +            # - symlinks: GCC 13 has FIXME notes for symlinks under Windows:
    


    fanquake commented at 11:59 AM on February 6, 2026:

    GCC 13 has FIXME notes for symlinks under Windows:

    I wonder if this will change. The FIXME has existed since 2018, when std::filesystem support for Windows was first added: https://github.com/gcc-mirror/gcc/commit/9534a5e62dc2b81d001f98f1ed582bc3f1d39c80.


    hodlinator commented at 10:15 AM on February 9, 2026:

    Updated the comment to document that it's still the case in latest release instead: https://github.com/bitcoin/bitcoin/blob/9a7b72560ec5b854c036cea8b19c5941650ed968/test/functional/wallet_multiwallet.py#L74-L79

    Hopefully that's slightly better for maintainability.

    Also dropped the comment about chmod as I don't think it really added anything relevant to this test beyond what the warning below already states.

  12. hodlinator commented at 10:31 AM on February 7, 2026: contributor

    Thanks for your review @janb84! At first I was astonished that the test succeeds for you on master. Then I realized that this PR actually makes the test work for Linux->Windows cross builds. Will make it clearer in the title/PR description.

  13. hodlinator renamed this:
    qa: Make wallet_multiwallet.py Windows-compatible
    qa: Make wallet_multiwallet.py Windows crossbuild-compatible
    on Feb 7, 2026
  14. hodlinator force-pushed on Feb 9, 2026
  15. DrahtBot added the label CI failed on Feb 9, 2026
  16. DrahtBot commented at 11:29 AM on February 9, 2026: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task Alpine (musl): https://github.com/bitcoin/bitcoin/actions/runs/21820908595/job/62953694277</sub> <sub>LLM reason (✨ experimental): mptest timed out (Timeout) causing the CI failure.</sub>

    <details><summary>Hints</summary>

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

    </details>

  17. janb84 commented at 12:46 PM on February 9, 2026: contributor

    ACK 9a7b72560ec5b854c036cea8b19c5941650ed968

    I revisited the PR, now using a cross compilation build. Using gcc, the master branch functional test will indeed fail to run:

    <details><summary>Master</summary>

    Temporary test directory at C:\Users\user\AppData\Local\Temp/test_runner_β‚Ώ_πŸƒ_20260209_120146
    Remaining jobs: [wallet_multiwallet.py, wallet_multiwallet.py --usecli]
    1/2 - wallet_multiwallet.py failed, Duration: 4 s
    
    stdout:
    2026-02-09T11:01:50.077850Z TestFramework (INFO): PRNG seed is: 4370893628585504645
    2026-02-09T11:01:50.136334Z TestFramework (INFO): Initializing test directory C:\Users\user\AppData\Local\Temp\test_runner_β‚Ώ_πŸƒ_20260209_120146\wallet_multiwallet_1
    2026-02-09T11:01:51.071252Z TestFramework (INFO): Verify warning is emitted when failing to scan the wallets directory
    2026-02-09T11:01:51.071428Z TestFramework (WARNING): Skipping test involving chmod as Windows does not support it.
    2026-02-09T11:01:54.529466Z TestFramework (ERROR): Unexpected exception
    Traceback (most recent call last):
      File "C:\Users\user\bitcoin\build\test\functional\test_framework\test_framework.py", line 142, in main
        self.run_test()
        ~~~~~~~~~~~~~^^
      File "C:\Users\user\bitcoin\build\/test/functional/wallet_multiwallet.py", line 150, in run_test
        with self.nodes[0].assert_debug_log(expected_msgs=["Error while scanning wallet dir"]):
             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "C:\Users\user\AppData\Local\Programs\Python\Python314\Lib\contextlib.py", line 148, in __exit__
        next(self.gen)
        ~~~~^^^^^^^^^^
      File "C:\Users\user\bitcoin\build\test\functional\test_framework\test_node.py", line 584, in assert_debug_log
        self._raise_assertion_error(f'Expected message(s) {remaining_expected!s} '
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                    f'not found in log:\n\n{join_log(log)}\n\n')
                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "C:\Users\user\bitcoin\build\test\functional\test_framework\test_node.py", line 229, in _raise_assertion_error
        raise AssertionError(self._node_msg(msg))
    AssertionError: [node 0] Expected message(s) ['Error while scanning wallet dir'] not found in log:
    
     - 2026-02-09T11:01:52.527937Z [http] [httpserver.cpp:307] [http_request_cb] [http] Received a POST request for / from 127.0.0.1:59769
     - 2026-02-09T11:01:52.528211Z [httpworker.0] [rpc/request.cpp:243] [parse] [rpc] ThreadRPCServer method=listwalletdir user=__cookie__
     - 2026-02-09T11:01:52.623421Z [httpworker.0] [wallet/db.cpp:69] [ListDatabases] [warning] Error scanning directory entries under C:\Users\user\AppData\Local\Temp\test_runner_β‚Ώ_πŸƒ_20260209_120146\wallet_multiwallet_1\node0\regtest\wallets: No such file or directory
    
    
    2026-02-09T11:01:54.584969Z TestFramework (INFO): Not stopping nodes as test failed. The dangling processes will be cleaned up later.
    2026-02-09T11:01:54.585174Z TestFramework (WARNING): Not cleaning up dir C:\Users\user\AppData\Local\Temp\test_runner_β‚Ώ_πŸƒ_20260209_120146\wallet_multiwallet_1
    2026-02-09T11:01:54.585290Z TestFramework (ERROR): Test failed. Test logging available at C:\Users\user\AppData\Local\Temp\test_runner_β‚Ώ_πŸƒ_20260209_120146\wallet_multiwallet_1/test_framework.log
    2026-02-09T11:01:54.585616Z TestFramework (ERROR):
    2026-02-09T11:01:54.586080Z TestFramework (ERROR): Hint: Call C:\Users\user\bitcoin\build\test\functional\combine_logs.py 'C:\Users\user\AppData\Local\Temp\test_runner_β‚Ώ_πŸƒ_20260209_120146\wallet_multiwallet_1' to consolidate all logs
    2026-02-09T11:01:54.586260Z TestFramework (ERROR):
    2026-02-09T11:01:54.586372Z TestFramework (ERROR): If this failure happened unexpectedly or intermittently, please file a bug and provide a link or upload of the combined log.
    2026-02-09T11:01:54.586471Z TestFramework (ERROR): https://github.com/bitcoin/bitcoin/issues
    2026-02-09T11:01:54.586540Z TestFramework (ERROR):
    
    
    stderr:
    [node 0] Cleaning up leftover process
    
    
    Remaining jobs: [wallet_multiwallet.py --usecli]
    2/2 - wallet_multiwallet.py --usecli failed, Duration: 6 s
    
    stdout:
    2026-02-09T11:01:50.088312Z TestFramework (INFO): PRNG seed is: 8248417181429283859
    2026-02-09T11:01:50.138382Z TestFramework (INFO): Initializing test directory C:\Users\user\AppData\Local\Temp\test_runner_β‚Ώ_πŸƒ_20260209_120146\wallet_multiwallet_0
    2026-02-09T11:01:51.977816Z TestFramework (INFO): Verify warning is emitted when failing to scan the wallets directory
    2026-02-09T11:01:51.978010Z TestFramework (WARNING): Skipping test involving chmod as Windows does not support it.
    2026-02-09T11:01:55.794679Z TestFramework (ERROR): Unexpected exception
    Traceback (most recent call last):
      File "C:\Users\user\bitcoin\build\test\functional\test_framework\test_framework.py", line 142, in main
        self.run_test()
        ~~~~~~~~~~~~~^^
      File "C:\Users\user\bitcoin\build\/test/functional/wallet_multiwallet.py", line 150, in run_test
        with self.nodes[0].assert_debug_log(expected_msgs=["Error while scanning wallet dir"]):
             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "C:\Users\user\AppData\Local\Programs\Python\Python314\Lib\contextlib.py", line 148, in __exit__
        next(self.gen)
        ~~~~^^^^^^^^^^
      File "C:\Users\user\bitcoin\build\test\functional\test_framework\test_node.py", line 584, in assert_debug_log
        self._raise_assertion_error(f'Expected message(s) {remaining_expected!s} '
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                    f'not found in log:\n\n{join_log(log)}\n\n')
                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "C:\Users\user\bitcoin\build\test\functional\test_framework\test_node.py", line 229, in _raise_assertion_error
        raise AssertionError(self._node_msg(msg))
    AssertionError: [node 0] Expected message(s) ['Error while scanning wallet dir'] not found in log:
    
     - 2026-02-09T11:01:53.850291Z [http] [httpserver.cpp:307] [http_request_cb] [http] Received a POST request for / from 127.0.0.1:59814
     - 2026-02-09T11:01:53.850472Z [httpworker.1] [rpc/request.cpp:243] [parse] [rpc] ThreadRPCServer method=listwalletdir user=__cookie__
     - 2026-02-09T11:01:53.936116Z [httpworker.1] [wallet/db.cpp:69] [ListDatabases] [warning] Error scanning directory entries under C:\Users\user\AppData\Local\Temp\test_runner_β‚Ώ_πŸƒ_20260209_120146\wallet_multiwallet_0\node0\regtest\wallets: No such file or directory
    
    
    2026-02-09T11:01:55.850081Z TestFramework (INFO): Not stopping nodes as test failed. The dangling processes will be cleaned up later.
    2026-02-09T11:01:55.850322Z TestFramework (WARNING): Not cleaning up dir C:\Users\user\AppData\Local\Temp\test_runner_β‚Ώ_πŸƒ_20260209_120146\wallet_multiwallet_0
    2026-02-09T11:01:55.850430Z TestFramework (ERROR): Test failed. Test logging available at C:\Users\user\AppData\Local\Temp\test_runner_β‚Ώ_πŸƒ_20260209_120146\wallet_multiwallet_0/test_framework.log
    2026-02-09T11:01:55.850616Z TestFramework (ERROR):
    2026-02-09T11:01:55.851275Z TestFramework (ERROR): Hint: Call C:\Users\user\bitcoin\build\test\functional\combine_logs.py 'C:\Users\user\AppData\Local\Temp\test_runner_β‚Ώ_πŸƒ_20260209_120146\wallet_multiwallet_0' to consolidate all logs
    2026-02-09T11:01:55.851362Z TestFramework (ERROR):
    2026-02-09T11:01:55.851432Z TestFramework (ERROR): If this failure happened unexpectedly or intermittently, please file a bug and provide a link or upload of the combined log.
    2026-02-09T11:01:55.851523Z TestFramework (ERROR): https://github.com/bitcoin/bitcoin/issues
    2026-02-09T11:01:55.851626Z TestFramework (ERROR):
    
    
    stderr:
    [node 0] Cleaning up leftover process
    
    
    
    TEST                           | STATUS    | DURATION
    
    wallet_multiwallet.py          | βœ– Failed  | 4 s
    wallet_multiwallet.py --usecli | βœ– Failed  | 6 s
    
    ALL                            | βœ– Failed  | 10 s (accumulated)
    

    </details>

    Using the same cross compilation build, this PR fixes the functional test:

    <details><summary>PR</summary>

    python .\build\test\functional\test_runner.py wallet_multiwallet.py
    Temporary test directory at C:\Users\user\AppData\Local\Temp/test_runner_β‚Ώ_πŸƒ_20260209_132101
    Remaining jobs: [wallet_multiwallet.py, wallet_multiwallet.py --usecli]
    1/2 - wallet_multiwallet.py passed, Duration: 14 s
    Remaining jobs: [wallet_multiwallet.py --usecli]
    2/2 - wallet_multiwallet.py --usecli passed, Duration: 24 s
    
    TEST                           | STATUS    | DURATION
    
    wallet_multiwallet.py          | βœ“ Passed  | 14 s
    wallet_multiwallet.py --usecli | βœ“ Passed  | 24 s
    
    ALL                            | βœ“ Passed  | 38 s (accumulated)
    Runtime: 24 s
    

    </details>

  18. DrahtBot removed the label CI failed on Feb 10, 2026
  19. DrahtBot added the label Needs rebase on Feb 13, 2026
  20. hodlinator force-pushed on Feb 13, 2026
  21. hodlinator commented at 8:29 PM on February 13, 2026: contributor

    Latest push resolves conflict with master where exclusion of wallet_multiwallet.py was moved from ci.yml to ci-windows-cross.py.

  22. DrahtBot removed the label Needs rebase on Feb 13, 2026
  23. janb84 commented at 1:49 PM on February 16, 2026: contributor

    re ACK 022b6e7c594dfa0a90aa1865e70160aa1317523d

  24. in test/functional/wallet_multiwallet.py:128 in 022b6e7c59 outdated
     160 | +        self.log.info("Test mixed wallets")
     161 |          # create symlink to verify wallet directory path can be referenced
     162 |          # through symlink
     163 | -        os.mkdir(wallet_dir('w7'))
     164 | -        os.symlink('w7', wallet_dir('w7_symlink'))
     165 | +        os.mkdir(wallet_dir(node, 'w7'))
    


    w0xlt commented at 2:33 AM on February 18, 2026:

    nit: not tested, but symlink-specific setup and checks could be skipped when symlink creation isn’t supported.

    <details> <summary>diff (just moved `os.symlink`/`w7` under `self.check_symlinks`) </summary>

         def test_mixed_wallets(self, node):
             self.log.info("Test mixed wallets")
    -        # create symlink to verify wallet directory path can be referenced
    -        # through symlink
    -        os.mkdir(wallet_dir(node, 'w7'))
    -        os.symlink('w7', wallet_dir(node, 'w7_symlink'))
    -
             if self.check_symlinks:
    +            # Create symlink to verify wallet directory path can be referenced through symlink.
    +            os.mkdir(wallet_dir(node, 'w7'))
    -        os.mkdir(wallet_dir(node, 'w7'))
    -        os.symlink('w7', wallet_dir(node, 'w7_symlink'))
    -
             if self.check_symlinks:
    +            # Create symlink to verify wallet directory path can be referenced through symlink.
    +            os.mkdir(wallet_dir(node, 'w7'))
    +            os.symlink('w7', wallet_dir(node, 'w7_symlink'))
                 os.symlink('..', wallet_dir(node, 'recursive_dir_symlink'))
     
             # rename wallet.dat to make sure plain wallet file paths (as opposed to
    @@ -153,12 +147,15 @@ class MultiWalletTest(BitcoinTestFramework):
             #   w          - to verify wallet name matching works when one wallet path is prefix of another
             #   sub/w5     - to verify relative wallet path is created correctly
             #   extern/w6  - to verify absolute wallet path is created correctly
    -        #   w7_symlink - to verify symlinked wallet path is initialized correctly
    +        #   w7_symlink - to verify symlinked wallet path is initialized correctly (symlink-capable platforms only)
             #   w8         - to verify existing wallet file is loaded correctly. Not tested for SQLite wallets as this is a deprecated BDB behavior.
             #   ''         - to verify default wallet file is created correctly
    -        to_create = ['w1', 'w2', 'w3', 'w', 'sub/w5', 'w7_symlink']
    +        to_create = ['w1', 'w2', 'w3', 'w', 'sub/w5']
    +        if self.check_symlinks:
    +            to_create.append('w7_symlink')
             in_wallet_dir = [w.replace('/', os.path.sep) for w in to_create]  # Wallets in the wallet dir
    -        in_wallet_dir.append('w7')  # w7 is not loaded or created, but will be listed by listwalletdir because w7_symlink
    +        if self.check_symlinks:
    +            in_wallet_dir.append('w7')  # w7 is not loaded or created, but will be listed by listwalletdir because w7_symlink
             to_create.append(os.path.join(self.options.tmpdir, 'extern/w6'))  # External, not in the wallet dir, so we need to avoid adding it to in_wallet_dir
             to_load = [self.default_wallet_name]
    :
    -        os.mkdir(wallet_dir(node, 'w7'))
    -        os.symlink('w7', wallet_dir(node, 'w7_symlink'))
    -
             if self.check_symlinks:
    +            # Create symlink to verify wallet directory path can be referenced through symlink.
    +            os.mkdir(wallet_dir(node, 'w7'))
    +            os.symlink('w7', wallet_dir(node, 'w7_symlink'))
                 os.symlink('..', wallet_dir(node, 'recursive_dir_symlink'))
     
             # rename wallet.dat to make sure plain wallet file paths (as opposed to
    @@ -153,12 +147,15 @@ class MultiWalletTest(BitcoinTestFramework):
             #   w          - to verify wallet name matching works when one wallet path is prefix of another
             #   sub/w5     - to verify relative wallet path is created correctly
             #   extern/w6  - to verify absolute wallet path is created correctly
    -        #   w7_symlink - to verify symlinked wallet path is initialized correctly
    +        #   w7_symlink - to verify symlinked wallet path is initialized correctly (symlink-capable platforms only)
             #   w8         - to verify existing wallet file is loaded correctly. Not tested for SQLite wallets as this is a deprecated BDB behavior.
             #   ''         - to verify default wallet file is created correctly
    -        to_create = ['w1', 'w2', 'w3', 'w', 'sub/w5', 'w7_symlink']
    +        to_create = ['w1', 'w2', 'w3', 'w', 'sub/w5']
    +        if self.check_symlinks:
    +            to_create.append('w7_symlink')
             in_wallet_dir = [w.replace('/', os.path.sep) for w in to_create]  # Wallets in the wallet dir
    -        in_wallet_dir.append('w7')  # w7 is not loaded or created, but will be listed by listwalletdir because w7_symlink
    +        if self.check_symlinks:
    +            in_wallet_dir.append('w7')  # w7 is not loaded or created, but will be listed by listwalletdir because w7_symlink
             to_create.append(os.path.join(self.options.tmpdir, 'extern/w6'))  # External, not in the wallet dir, so we need to avoid adding it to in_wallet_dir
             to_load = [self.default_wallet_name]
    
    

    </details>


    maflcko commented at 10:16 AM on February 18, 2026:

    nit: not tested, but symlink-specific setup and checks could be skipped when symlink creation isn’t supported.

    Why would that be better? That just makes it harder to enable in the future: E.g via commit 677297e8522a81225bc537795f51468e49d85f5a


    hodlinator commented at 8:09 PM on February 18, 2026:

    I considered avoiding all symlink creation instead of just what caused issues, but felt it would make the code more cumbersome. Hadn't foreseen #34603 - that's promising, and another argument for keeping a smaller diff.

    Leaning towards making a note of my reasoning in the commit message if I re-touch.


    w0xlt commented at 12:26 AM on February 19, 2026:

    Yes, symlink creation isn’t an issue on CI (or in most developer environments), so there’s no problem. The only case where it might matter is when reproducing a user’s environment, but #34603 will likely handle that.


    hodlinator commented at 8:56 AM on February 19, 2026:

    Added note in commit message in latest push.

  25. DrahtBot requested review from w0xlt on Feb 18, 2026
  26. gniumg-source referenced this in commit a93cf6c8d2 on Feb 18, 2026
  27. gniumg-source referenced this in commit e73f089772 on Feb 18, 2026
  28. w0xlt commented at 12:26 AM on February 19, 2026: contributor

    ACK 022b6e7c594dfa0a90aa1865e70160aa1317523d

  29. DrahtBot added the label Needs rebase on Feb 19, 2026
  30. refactor(qa): Remove unused option
    Last use was removed in 0d32d661481f099af572e7a08a50e17bcc165c44.
    73cf858911
  31. scripted-diff: self.nodes[0] => node
    -BEGIN VERIFY SCRIPT-
    sed --in-place 's/self\.nodes\[0\]/node/g; s/node \= node/node \= self\.nodes\[0\]/' ./test/functional/wallet_multiwallet.py
    -END VERIFY SCRIPT-
    c811e47367
  32. refactor(qa): Lift out functions to outer scopes
    This prepares for later breaking apart of run_test().
    
    Note that the "wallet" lambda was renamed to "get_wallet" since otherwise the Python interpreter emitted:
    "UnboundLocalError: cannot access local variable 'wallet' where it is not associated with a value"
    d1a4ddb58e
  33. move-only(qa): Move wallet creation check down to others
    Makes the functions broken out from run_test() in the next commit more cohesive.
    bb1aff7ed7
  34. refactor(qa): Break apart ginormous run_test() 64a098a9b6
  35. qa: Check for platform-independent part of error message
    On Windows one gets different exception messages depending on whether running a native build or cross build.
    ed43ce57cc
  36. qa: Test scanning errors individually
    This change ensures that each condition potentially triggering the
    "Error while scanning" log message is tested independently, avoiding
    false positives.
    
    Co-authored-by: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com>
    fb803e3c79
  37. qa: Disable parts of the test when running under Windows or root
    test_scanning_sub_dir():
    - Remove try/finally - we don't need to clean up after a failed test (done in this commit to maintain indentation).
    
    Regarding symlinks: https://github.com/bitcoin/bitcoin/pull/31410#issuecomment-3554721014
    
    Kept some symlink creation which didn't disrupt Windows cross builds to make for a smaller diff and less cumbersome code. There is some hope of eventually getting better symlink support via #34603.
    
    Co-authored-by: Ava Chow <github@achow101.com>
    850a80c199
  38. ci: Enable `wallet_multiwallet.py` in "Windows, test cross-built" job
    Co-authored-by: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com>
    c2e28d455a
  39. qa: Avoid duplicating output in case the diff is the same 111864ac30
  40. hodlinator force-pushed on Feb 19, 2026
  41. hodlinator commented at 8:57 AM on February 19, 2026: contributor

    Latest push resolves conflict with 331a5279d2775fb701a0bf4607436ec05e476df3 / #32138.

  42. DrahtBot removed the label Needs rebase on Feb 19, 2026
  43. janb84 commented at 10:08 AM on February 19, 2026: contributor

    re ACK 111864ac30126dc64a9e21d4e1b5e3d9ef4e5358

  44. DrahtBot requested review from w0xlt on Feb 19, 2026
  45. w0xlt commented at 11:58 PM on February 19, 2026: contributor

    reACK 111864ac30126dc64a9e21d4e1b5e3d9ef4e5358

  46. DrahtBot requested review from w0xlt on Feb 19, 2026
  47. achow101 commented at 10:38 PM on March 13, 2026: member

    ACK 111864ac30126dc64a9e21d4e1b5e3d9ef4e5358

  48. achow101 merged this on Mar 13, 2026
  49. achow101 closed this on Mar 13, 2026

  50. hebasto commented at 2:22 PM on March 16, 2026: member

    https://github.com/hebasto/bitcoin-core-nightly/actions/runs/23142303396/job/67225418373:

    wallet_multiwallet.py                                                            | βœ– Failed  | 10 s
    wallet_multiwallet.py --usecli                                                   | βœ– Failed  | 13 s
    
  51. maflcko commented at 2:30 PM on March 16, 2026: member

    https://github.com/hebasto/bitcoin-core-nightly/actions/runs/23142303396/job/67225418373:

    wallet_multiwallet.py                                                            | βœ– Failed  | 10 s
    wallet_multiwallet.py --usecli                                                   | βœ– Failed  | 13 s
    

    This looks like an upstream bug? It claims the error message is (literally): error message: 'basic_string'. Whereas it should contain anything meaningfully like Wallet file verification failed. or std::file_system error ... or similar.

  52. fanquake commented at 2:45 PM on March 16, 2026: member

    https://github.com/hebasto/bitcoin-core-nightly/actions/runs/23142303396/job/67225418373: @hebasto do we have any CI in this repo that tests the changes made here? If so, what is the difference between it, and your CI that is failing?

  53. hebasto commented at 3:01 PM on March 16, 2026: member

    https://github.com/hebasto/bitcoin-core-nightly/actions/runs/23142303396/job/67225418373:

    @hebasto do we have any CI in this repo that tests the changes made here? If so, what is the difference between it, and your CI that is failing?

    It's Windows ARM64. No other differences.

  54. maflcko commented at 3:39 PM on March 16, 2026: member

    I think it could make sense to properly track, minimize, and report it upstream. Leaving a comment here seems fine, but I don't think anyone is actively monitoring closed pull requests.

  55. hebasto commented at 3:35 PM on March 19, 2026: member

    https://github.com/hebasto/bitcoin-core-nightly/actions/runs/23142303396/job/67225418373:

    wallet_multiwallet.py                                                            | βœ– Failed  | 10 s
    wallet_multiwallet.py --usecli                                                   | βœ– Failed  | 13 s
    

    See https://github.com/hebasto/bitcoin-core-nightly/issues/213.

  56. hodlinator deleted the branch on Apr 9, 2026

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: 2026-04-14 21:12 UTC

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