Skip to content

multiprocess: Add bitcoin wrapper executable - #31375

Merged
achow101 merged 7 commits into
bitcoin:masterfrom
ryanofsky:pr/wrap
May 27, 2025
Merged

multiprocess: Add bitcoin wrapper executable#31375
achow101 merged 7 commits into
bitcoin:masterfrom
ryanofsky:pr/wrap

Conversation

@ryanofsky

@ryanofsky ryanofsky commented Nov 26, 2024

Copy link
Copy Markdown
Contributor

Intended to make bitcoin command line features more discoverable and allow installing new multiprocess binaries in libexec/ instead of bin/ so they don't cause confusion.

Idea and implementation of this were discussed in #30983.


Initial implementation of this feature is deliberately minimal so the UX can evolve in response to feedback and there are not too many details to debate and discuss in a single PR. But many improvements are possible or planned:

  • Adding manpage and bash completions.
  • Showing nicer error messages that detect if an executable isn't installed and suggest how to fix (comment)
  • Showing wrapper command lines in subcommand in help output (comment). This could be done conditionally as suggested in the comment or be unconditional.
  • Showing wrapper command lines in subcommand error output. There is a bitcoin-cli error pointed out in (comment) that is needlessly confusing.
  • Integrating help so bitcoin help subcommand invokes bitcoin subcommand -h. bitcoin -h subcommand should also be supported and be equivalent (comment)
  • Adding support for bitcoin-util subcommands. Ideal interface would probably be more like bitcoin grind not bitcoin util grind but this has been punted for now. Supporting subcommands directly would require some ArgsManager modifications
  • Adding a dedicated python functional test for the wrapper. Right now there is some CI coverage by setting the BITCOIN_CMD variable, but this doesn't cover things like the help output and version output, and support for different directory layouts.
  • Better --multiprocess (-m) / --monolithic (-M) default selection. Right now, default is monolithic but it probably makes sense to chose more intelligently depending on whether -ipc options are enabled and what binaries are available.
  • Maybe parsing bitcoin.conf and supporting options to control wrapper behavior like custom locations or preferences or aliases.
  • Better command command line usability. Allow combining short options like (-ah). Allow fuzzy matching of subcommands or suggestions if you misspell. (suggested by stickies in review club)
  • Not directly related to this PR but bitcoin-cli named implementation used by the wrapper should do a better job disambiguating named arguments from base64 arguments ending in = as pointed out in (comment)

This PR is part of the process separation project. A review club meeting for it took place in https://bitcoincore.reviews/31375

@DrahtBot

DrahtBot commented Nov 26, 2024

Copy link
Copy Markdown
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/31375.

Reviews

See the guideline for information on the review process.

Type Reviewers
ACK vasild, theStack, ismaelsadeeq, Sjors, hodlinator, achow101
Approach ACK TheCharlatan

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:

  • #32297 (bitcoin-cli: Add -ipcconnect option by ryanofsky)
  • #30437 (ipc: add bitcoin-mine test program by ryanofsky)
  • #28690 (build: Introduce internal kernel library by TheCharlatan)

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.

@DrahtBot

Copy link
Copy Markdown
Contributor

🚧 At least one of the CI tasks failed.
Debug: https://github.com/bitcoin/bitcoin/runs/33557375133

Hints

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.

@ryanofsky

ryanofsky commented Nov 27, 2024

Copy link
Copy Markdown
Contributor Author

Updated 19ae652 -> 63df9f3 (pr/wrap.3 -> pr/wrap.4, compare) with fixes for windows and fuzz CI errors, and lint and tidy fixes
Updated 63df9f3 -> da108a6 (pr/wrap.4 -> pr/wrap.5, compare) fixing windows include error, fs lint error, and previous releases test bug

@Sjors Sjors left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK

I think it would be more clear to move build/src/bitcoin-{node,gui} to build/src/libexec, rather than use a different file organization for CMake builds than for installs.

The "Win64 native, VS 2022" job still seems unhappy.

Comment thread src/bitcoin.cpp
@hebasto

hebasto commented Nov 28, 2024

Copy link
Copy Markdown
Member

The "Win64 native, VS 2022" job still seems unhappy.

https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-3-c4996?view=msvc-170#posix-function-names:

To turn off deprecation warnings for these functions, define the preprocessor macro _CRT_NONSTDC_NO_WARNINGS. You can define this macro at the command line by including the option /D_CRT_NONSTDC_NO_WARNINGS.

We have already used this macro:

target_compile_definitions(nowarn_leveldb_interface INTERFACE
_CRT_NONSTDC_NO_WARNINGS
)

@ryanofsky ryanofsky left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the reviews!

Updated da108a6 -> 02567bf (pr/wrap.5 -> pr/wrap.6, compare) to fix windows build warning and making a change to avoid a potentially confusing behavior #31375 (comment)


re: #31375 (review)

I think it would be more clear to move build/src/bitcoin-{node,gui} to build/src/libexec, rather than use a different file organization for CMake builds than for installs.

Agree and I think #31161 should allow this to be simplified.


re: #31375 (comment)

We have already used this macro:

target_compile_definitions(nowarn_leveldb_interface INTERFACE
_CRT_NONSTDC_NO_WARNINGS
)

It seems like it would be better if this code could be compiled without disabling warnings, especially since if the old names are being deprecated. For now I just added a #define to switch to the recommended name. For leveldb it probably does make sense to disable the warnings to avoid needing to change the code too much.

Comment thread src/bitcoin.cpp
@maflcko

maflcko commented Dec 4, 2024

Copy link
Copy Markdown
Member

For reference the CI failure is:

                                   subprocess.CalledProcessError: Command '['C:\\hostedtoolcache\\windows\\Python\\3.12.7\\x64\\python.exe', 'D:/a/bitcoin/bitcoin\\contrib\\signet\\miner', "--cli='D:\\a\\bitcoin\\bitcoin\\build\\src\\Release\\bitcoin-cli.exe' -nonamed '-datadir=D:\\a\\_temp\\test_runner_₿_🏃_20241203_223434\\tool_signet_miner_211\\node0'", 'generate', '--address=tb1q2ndfasp67k5wp30fkt63tw9gf465lcjf7rm5fc', "--grind-cmd='D:\\a\\bitcoin\\bitcoin\\build\\src\\Release\\bitcoin-util.exe' grind", '--nbits=1d00ffff', '--set-block-time=1733265821', '--poolnum=99']' returned non-zero exit status 1.

Earlier it says:

FileNotFoundError: [WinError 2] The system cannot find the file specified

@ryanofsky

Copy link
Copy Markdown
Contributor Author

Updated 02567bf -> 2def75a (pr/wrap.6 -> pr/wrap.7, compare) to fix argument parsing bug causing a test failure on windows https://github.com/bitcoin/bitcoin/actions/runs/12147886951/job/33875123699?pr=31375#step:12:95

@ryanofsky

Copy link
Copy Markdown
Contributor Author

Rebased 2def75a -> 637b01f (pr/wrap.7 -> pr/wrap.8, compare) due to conflict with #30933

@hodlinator hodlinator left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review 4e1aae1

Seems like a slight fix would be good in the NSI script, see inline comment.

Nice simplification of ExecVp since previous review.

Tested on NixOS.

Tested redirection of stderr/stdout

./build/bin/bitcoin node > foo
./build/bin/bitcoin node --nonexistentarg 2> err

"foo" stdout file contains expected log output. Confirmed by changing bitcoind.cpp error message that it was properly writing to "err" stderr file.

Tested moving bitcoin executable

Ensured /src was in $PATH and copied bitcoin executable there. Gives expected error messages:

~/bitcoin/src
₿ bitcoin node --nonexistentarg 
Error: execvp failed to execute 'bitcoind': No such file or directory
Try 'bitcoin --help' for more information.

~/bitcoin/src
₿ ./bitcoin node --nonexistentarg 
Error: execvp failed to execute '/home/hodlinator/bitcoin/src/bitcoind': No such file or directory
Try './bitcoin --help' for more information.

Comment thread src/util/exec.h
Comment thread src/util/exec.cpp
Comment thread src/util/exec.cpp
Comment thread src/util/exec.cpp
Comment thread doc/multisig-tutorial.md
Comment thread share/setup.nsi.in

@ryanofsky ryanofsky left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated 4e1aae1 -> 7af6e10 (pr/wrap.32 -> pr/wrap.33, compare) with suggestions adding windows uninstall line, removing no longer used cmake build prefixes, and improving many comments.

Comment thread src/bitcoin.cpp Outdated
Comment thread src/bitcoin.cpp Outdated
Comment thread src/util/exec.h
Comment thread src/util/exec.cpp
Comment thread src/util/exec.cpp
Comment thread src/util/exec.cpp
Comment thread doc/multisig-tutorial.md
Comment thread share/setup.nsi.in
@Sjors

Sjors commented May 15, 2025

Copy link
Copy Markdown
Member

re-utACK 7af6e10

I didn't retest.

@ismaelsadeeq ismaelsadeeq left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review 7af6e10

I've also tested this on macOS.

It was running smoothly. I tried shutting it down using the CLI interface, and it worked as expected.

However, I encountered an issue when performing an unclean shutdown using CTRL+C.
The process hung, and I had to pkill bitcoind to terminate it.

I wasn’t running with -debug option, so I couldn’t figure out exactly what went wrong. I tried to reproduce the issue but couldn’t It worked smoothly in all subsequent runs and shutdown even during unclean shutdown.
Because of that, I would encourage additional testing on all supported platforms.

I also have some comments and a suggestion to help prevent mixing up options with commands.

Comment thread src/bitcoin.cpp Outdated
Comment thread CMakeLists.txt
Comment thread src/bitcoin.cpp Outdated
Comment thread src/bitcoin.cpp
Comment thread src/bitcoin.cpp
Comment thread src/bitcoin.cpp

@ryanofsky ryanofsky left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the reviews!

Updated 7af6e10 -> a5ac43d (pr/wrap.33 -> pr/wrap.34, compare) just updating copyright and adding exception to handle an unexpected condition

re: #31375 (review)

However, I encountered an issue when performing an unclean shutdown using CTRL+C.

This could be a real issue but I somewhat doubt this PR could cause something like that. Unless the wrapper executable is printing help or error output should only be making a single exec call, so there is very little it could be doing to influence the next executable that is started.

Comment thread src/bitcoin.cpp Outdated
Comment thread src/bitcoin.cpp Outdated
Comment thread src/bitcoin.cpp
Comment thread src/bitcoin.cpp
Comment thread src/bitcoin.cpp
Comment thread doc/multisig-tutorial.md
Comment thread CMakeLists.txt

@vasild vasild left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK a5ac43d

Comment thread src/bitcoin.cpp
Comment on lines +167 to +171
if (util::ExecVp(exec_args[0], (char*const*)exec_args.data()) == -1) {
if (allow_notfound && errno == ENOENT) return false;
throw std::system_error(errno, std::system_category(), strprintf("execvp failed to execute '%s'", exec_args[0]));
}
throw std::runtime_error("execvp returned unexpectedly");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be written like:

util::ExecVp(exec_args[0], (char*const*)exec_args.data()); // If it returns then an error has occurred.

if (allow_notfound && errno == ENOENT) return false;
throw std::system_error(errno, std::system_category(), strprintf("execvp failed to execute '%s'", exec_args[0]));

it is less indentation and less code - no need for the "this will never be reached" throw.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re: #31375 (comment)

execvp is documented to return -1 if there is an error (https://linux.die.net/man/3/execvp and https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/execvp-wexecvp) so if it returns something else I think it is better to abort and not just keep going.

Comment thread src/util/exec.h
Comment on lines +15 to +16
//! array should consist of null terminated strings and be null terminated
//! itself, like the POSIX function.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super nit, but I can't resist ⛑️ :

"null terminated strings" and "null terminated" array -- it is not the same "null":

Suggested change
//! array should consist of null terminated strings and be null terminated
//! itself, like the POSIX function.
//! array should consist of '\0'-terminated strings and be nullptr-terminated
//! itself, like the POSIX function.

🏃

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re: #31375 (comment)

Yes I used to refer to them as NUL terminated strings, until I came across https://en.wikipedia.org/wiki/Null-terminated_string and decided there wasn't any real ambiguity and null was probably easier to read. But would be ok changing this if others would prefer

@ryanofsky ryanofsky left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for reviewing again!

Comment thread src/bitcoin.cpp
Comment on lines +167 to +171
if (util::ExecVp(exec_args[0], (char*const*)exec_args.data()) == -1) {
if (allow_notfound && errno == ENOENT) return false;
throw std::system_error(errno, std::system_category(), strprintf("execvp failed to execute '%s'", exec_args[0]));
}
throw std::runtime_error("execvp returned unexpectedly");

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re: #31375 (comment)

execvp is documented to return -1 if there is an error (https://linux.die.net/man/3/execvp and https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/execvp-wexecvp) so if it returns something else I think it is better to abort and not just keep going.

Comment thread src/util/exec.h
Comment on lines +15 to +16
//! array should consist of null terminated strings and be null terminated
//! itself, like the POSIX function.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re: #31375 (comment)

Yes I used to refer to them as NUL terminated strings, until I came across https://en.wikipedia.org/wiki/Null-terminated_string and decided there wasn't any real ambiguity and null was probably easier to read. But would be ok changing this if others would prefer

@theStack theStack left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK a5ac43d

Tested the wrapper more in-depth on Debian Linux 12, both with monolithic and multiprocess binaries this time, and also tried calling the wrapper without path separator to test PATH searching. Everything worked fine. Reviewed the code, though I only lightly looked at the Windows-specific parts in the exec.cpp module. Left some small refactoring and a comment improvement nit below, nothing blocking.

Comment thread src/util/exec.cpp
Comment thread src/bitcoin.cpp
}

//! Execute the specified bitcoind, bitcoin-qt or other command line in `args`
//! using src, bin and libexec directory paths relative to this executable, where

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in commit 9c8c688: nit: the directory list seems outdated

Suggested change
//! using src, bin and libexec directory paths relative to this executable, where
//! using bin and libexec directory paths relative to this executable, where

(don't know if it's really that important, but could even mentioned the "daemon" directory on Windows)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re: #31375 (comment)

in commit 9c8c688: nit: the directory list seems outdated

Thanks! I made this change locally so it will be included here if there is another update, or in one of the followups.

Comment thread src/bitcoin.cpp

@ryanofsky ryanofsky left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review! This could be ready to merge with another ack

Comment thread src/util/exec.cpp
Comment thread src/bitcoin.cpp
}

//! Execute the specified bitcoind, bitcoin-qt or other command line in `args`
//! using src, bin and libexec directory paths relative to this executable, where

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re: #31375 (comment)

in commit 9c8c688: nit: the directory list seems outdated

Thanks! I made this change locally so it will be included here if there is another update, or in one of the followups.

Comment thread src/bitcoin.cpp

@ismaelsadeeq ismaelsadeeq left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw my last review implied an ACK a5ac43d

Further improvement can come after this as mentioned in the description, and also since I could not and no one reproduced the freeze I encountered in the unclean shutdown it is not a blocker to this.

@Sjors

Sjors commented May 23, 2025

Copy link
Copy Markdown
Member

utACK a5ac43d

Since my last review this just adds throw std::runtime_error("execvp returned unexpectedly") and the copyright change.

@hodlinator hodlinator left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK a5ac43d

Concept: #31375 (review)

git range-diff master 4e1aae1 a5ac43d shows only minor fixups since previous review (#31375 (review)).

@achow101

Copy link
Copy Markdown
Member

ACK a5ac43d

@hebasto

hebasto commented May 28, 2025

Copy link
Copy Markdown
Member

There seems a silent conflict with #32396.

@hebasto

hebasto commented May 28, 2025

Copy link
Copy Markdown
Member

There seems a silent conflict with #32396.

Addressed in #32634.

@fanquake

fanquake commented Sep 9, 2025

Copy link
Copy Markdown
Member

gen-manpages.py followup in #33348.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

Development

Successfully merging this pull request may close these issues.