util: Improve documentation and negation of args #31212

pull hodlinator wants to merge 8 commits into bitcoin:master from hodlinator:2024/11/invalid_args changing 16 files +180 −53
  1. hodlinator commented at 2:15 pm on November 4, 2024: contributor
    • Document -color as only applying to -getinfo, to be less confusing for bitcoin-cli users.
    • No longer print version information when getting passed -noversion.
    • Disallow -nodatadir as we cannot run without one. It was previously interpreted as a mix of unset and as a relative path of “0”.
    • Support -norpccookiefile
    • Support -nopid
    • Properly support -noconf (instead of working by accident). Also detect when directories are specified instead of files.

    Prompted by investigation in #16545#pullrequestreview-2316714013.

  2. DrahtBot commented at 2:15 pm on November 4, 2024: 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/31212.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    Concept ACK rkrux, l0rinc

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

    Conflicts

    No conflicts as of last run.

  3. DrahtBot added the label Utils/log/libs on Nov 4, 2024
  4. in src/bitcoin-cli.cpp:96 in 1cfbe0ca22 outdated
    92@@ -93,7 +93,7 @@ static void SetupCliArgs(ArgsManager& argsman)
    93     argsman.AddArg("-netinfo", "Get network peer connection information from the remote server. An optional integer argument from 0 to 4 can be passed for different peers listings (default: 0). Pass \"help\" for detailed help documentation.", ArgsManager::ALLOW_ANY, OptionsCategory::CLI_COMMANDS);
    94 
    95     SetupChainParamsBaseOptions(argsman);
    96-    argsman.AddArg("-color=<when>", strprintf("Color setting for CLI output (default: %s). Valid values: always, auto (add color codes when standard output is connected to a terminal and OS is not WIN32), never.", DEFAULT_COLOR_SETTING), ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS);
    97+    argsman.AddArg("-color=<when>", strprintf("Color setting for CLI output (default: %s). Valid values: always, auto (add color codes when standard output is connected to a terminal and OS is not WIN32), never. Only applies in combination with -getinfo.", DEFAULT_COLOR_SETTING), ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS);
    


    rkrux commented at 10:20 am on November 7, 2024:

    Good catch. I was confused initially wondering why doesn’t color show up on explicitly setting this arg. in combination gives an impression that somehow both these args need to be passed together.

    0Only applies to the output of -getinfo.
    

    hodlinator commented at 12:58 pm on November 8, 2024:
    Thanks! Applied.
  5. in src/bitcoin-cli.cpp:148 in a8a41f1c96 outdated
    143@@ -144,10 +144,10 @@ static int AppInitRPC(int argc, char* argv[])
    144         tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error);
    145         return EXIT_FAILURE;
    146     }
    147-    if (argc < 2 || HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
    148+    if (argc < 2 || HelpRequested(gArgs) || gArgs.GetBoolArg("-version", false)) {
    


    rkrux commented at 10:24 am on November 7, 2024:

    Again great catch. I noticed the difference in the output in master and this branch.

     0➜  bitcoin git:(master) ✗ bitcoinclireg -noversion
     1Bitcoin Core RPC client version v28.99.0-65b194193661
     2Copyright (C) 2009-2024 The Bitcoin Core developers
     3
     4Please contribute if you find Bitcoin Core useful. Visit
     5<https://bitcoincore.org/> for further information about the software.
     6The source code is available from <https://github.com/bitcoin/bitcoin>.
     7
     8This is experimental software.
     9Distributed under the MIT software license, see the accompanying file COPYING
    10or <https://opensource.org/licenses/MIT>
    11
    12➜  bitcoin git:(master) ✗ bitcoinclireg -noversion
    13error: too few parameters (need at least command)
    

    Wondering now maybe we should disallow negation for version altogether? The output of noversion now is too few params and I fail to see any benefit in allowing this (maybe I’m missing something here). Might as well throw this error?

    0Negating of -version is meaningless and therefore forbidden
    

    hodlinator commented at 1:05 pm on November 8, 2024:

    I’m relying on this comment from unmerged #16545: https://github.com/bitcoin/bitcoin/blob/b5ef85497436c3e9e60c760465d8991592efef07/src/common/args.h#L112-L114

    One could imagine a user having a config file containing:

    0version=1
    1<...many lines...>
    2noversion=1
    

    The last occurrence of a bool option takes precedence. Agree it feels very contrived for this specific setting, but I’m trying to stick to the general principle of trying to allow negation if possible.

  6. rkrux commented at 10:59 am on November 7, 2024: none

    Concept ACK 9e130811a3f68aea77ddeecf667aa8389a2940e8

    Thanks for catching issues here, gave me an opportunity to read the app init code a bit more!

    Successful make and functional tests. Left couple suggestions in the first 2 commits. Disallowing noconf and nodatadir conceptually makes sense to me. I tested with these 2 args and the output I received seems okay to me.

    0➜  bitcoin git:(2024/11/invalid_args) ✗ bitcoinclireg -noconf
    1Error parsing command line arguments: Negating of -conf is meaningless and therefore forbidden
    2➜  bitcoin git:(2024/11/invalid_args) ✗ bitcoinclireg -nodatadir
    3Error parsing command line arguments: Negating of -datadir is meaningless and therefore forbidden
    

    Though I don’t completely understand why this comment “ok to not have a config file” (and subsequent flow) is allowed because when I ran the CLI without any arg I received the version info, help options, & too few args message. https://github.com/hodlinator/bitcoin/blob/2024/11/invalid_args/src/common/config.cpp#L138

  7. in src/bitcoin-cli.cpp:151 in a8a41f1c96 outdated
    143@@ -144,10 +144,10 @@ static int AppInitRPC(int argc, char* argv[])
    144         tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error);
    145         return EXIT_FAILURE;
    146     }
    147-    if (argc < 2 || HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
    148+    if (argc < 2 || HelpRequested(gArgs) || gArgs.GetBoolArg("-version", false)) {
    149         std::string strUsage = CLIENT_NAME " RPC client version " + FormatFullVersion() + "\n";
    150 
    151-        if (gArgs.IsArgSet("-version")) {
    152+        if (gArgs.GetBoolArg("-version", false)) {
    


    maflcko commented at 11:15 am on November 7, 2024:
    Could this commit be a scripted-diff?

    hodlinator commented at 1:05 pm on November 8, 2024:
    Done!
  8. rkrux commented at 12:25 pm on November 7, 2024: none

    Though I don’t completely understand why this comment “ok to not have a config file” (and subsequent flow) is allowed

    My guess it is applicable when the daemon is run without a conf because this portion lies in common/.

  9. hodlinator commented at 12:55 pm on November 8, 2024: contributor

    Though I don’t completely understand why this comment “ok to not have a config file” (and subsequent flow) is allowed

    My guess it is applicable when the daemon is run without a conf because this portion lies in common/.

    My interpretation is that we shouldn’t trigger an error on not finding a configuration file in the ~specified or~ default location. If it’s there we read it, otherwise just skip. (The code does error just above if one is unable to open a configuration file at a non-default location).

  10. hodlinator force-pushed on Nov 8, 2024
  11. DrahtBot added the label Needs rebase on Nov 8, 2024
  12. luke-jr commented at 6:40 pm on November 9, 2024: member

    Disallow -noconf since a config file is required

    But it’s not. Seems like -noconf should work to ignore the config file.

  13. hodlinator commented at 3:18 pm on November 11, 2024: contributor

    Disallow -noconf since a config file is required

    But it’s not. Seems like -noconf should work to ignore the config file.

    As mentioned in the commit message for 2d65e6ae0756b87e82dbafd032308e8687ec7941:

    ArgsManager::GetConfigFilePath() asserts that a path is always set. Explicitly negating it is therefore invalid."

    Previously, -noconf would result in an ifstream being opened to the “.bitcoin”-directory (not a file) in ArgsManager::ReadConfigFiles(), also circumventing the assert in aforementioned GetConfigFilePath().

    (-conf="" is still allowed to reset to the default bitcoin.conf-file location)."

    It’s sheer luck when it comes to how ifstream treats opening of directories that has allowed this before the PR.

    Here is GetConfigFilePath:

    https://github.com/bitcoin/bitcoin/blob/2d65e6ae0756b87e82dbafd032308e8687ec7941/src/common/args.cpp#L761-L765

    The part of ArgsManager::ReadConfigFiles which with -noconf would open a directory in the ifstream, and treat it as .good().

    https://github.com/bitcoin/bitcoin/blob/2d65e6ae0756b87e82dbafd032308e8687ec7941/src/common/config.cpp#L121-L140

    ReadConfigStream calls into GetConfigOptions which gets as far as trying to getline from the directory ifstream, only to return true (success).

    https://github.com/bitcoin/bitcoin/blob/2d65e6ae0756b87e82dbafd032308e8687ec7941/src/common/config.cpp#L33-L38

    It would be good to add detection of “directory as config path” and trigger an error, regardless of which path is given. But I’m still inclined to disallow -noconf because of the assert in GetConfigFilePath.

  14. l0rinc commented at 3:29 pm on November 11, 2024: contributor
    Concept ACK
  15. hodlinator commented at 3:52 pm on November 11, 2024: contributor
    Added commit which now guards against passing directory paths as -conf values as per #31212 (comment).
  16. ryanofsky commented at 1:18 pm on November 12, 2024: contributor

    Code review d9cfb2a314caa1cdcae8e47a03dad557ad96e069.

    This generally looks good except commit 2d65e6ae0756b87e82dbafd032308e8687ec7941 disallowing -noconf. Specifying -noconf to disable reading from the default config file path is useful and something that should be supported, even if now it’s only working in a very quirky way by treating the datadir as an empty configuration file. I think a better implementation would not look too different though, maybe like:

     0--- a/src/common/config.cpp
     1+++ b/src/common/config.cpp
     2@@ -131,7 +131,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
     3     std::ifstream stream{conf_path};
     4 
     5     // not ok to have a config file specified that cannot be opened
     6-    if (IsArgSet("-conf") && !stream.good()) {
     7+    if ((IsArgSet("-conf") && !IsArgNegated("-conf")) && !stream.good()) {
     8         error = strprintf("specified config file \"%s\" could not be opened.", fs::PathToString(conf_path));
     9         return false;
    10     }
    11@@ -213,7 +213,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
    12 
    13 fs::path AbsPathForConfigVal(const ArgsManager& args, const fs::path& path, bool net_specific)
    14 {
    15-    if (path.is_absolute()) {
    16+    if (path.is_absolute() || path.empty()) {
    17         return path;
    18     }
    19     return fsbridge::AbsPathJoin(net_specific ? args.GetDataDirNet() : args.GetDataDirBase(), path);
    

    I don’t think it’s right to infer from Assert(m_config_path) that a configuration file is always required by because that assert is really meant to catch initialization order bugs. The type of m_config_path is std::optional<fs::path> not fs::path so an empty path is ok there.

  17. hodlinator force-pushed on Nov 14, 2024
  18. hodlinator force-pushed on Nov 14, 2024
  19. hodlinator commented at 11:19 pm on November 14, 2024: contributor
    @ryanofsky thanks for the review! Updated to cover negation for all users of AbsPathForConfigVal.
  20. hodlinator renamed this:
    util: Narrow scope of args (-color, -version, -conf, -datadir)
    util: Improve documentation and negation of args (-color, -version, -datadir, -rpccookiefile, -pid, -conf)
    on Nov 14, 2024
  21. hodlinator renamed this:
    util: Improve documentation and negation of args (-color, -version, -datadir, -rpccookiefile, -pid, -conf)
    util: Improve documentation and negation of args
    on Nov 14, 2024
  22. in src/rpc/request.cpp:99 in cf3e4edc80 outdated
    95@@ -96,6 +96,11 @@ static bool g_generated_cookie = false;
    96 
    97 bool GenerateAuthCookie(std::string* cookie_out, std::optional<fs::perms> cookie_perms)
    98 {
    99+    if (gArgs.IsArgNegated("-rpccookiefile")) {
    


    ryanofsky commented at 3:24 am on November 15, 2024:

    In commit “args: Support -norpccookiefile” (cf3e4edc803bf950f280b24c5283a2838c86faf6)

    I think having two separate accesses to the -rpccookiefile in different functions is fragile since GetAuthCookieFile will not do the right thing if called in a different context. It is also not taking advantage of GetPathArg’s built in handling of negation. I think a change like:

     0--- a/src/rpc/request.cpp
     1+++ b/src/rpc/request.cpp
     2@@ -86,6 +86,7 @@ static const char* const COOKIEAUTH_FILE = ".cookie";
     3 static fs::path GetAuthCookieFile(bool temp=false)
     4 {
     5     fs::path arg = gArgs.GetPathArg("-rpccookiefile", COOKIEAUTH_FILE);
     6+    if (arg.empty()) return {}; // -norpccookiefile was specified
     7     if (temp) {
     8         arg += ".tmp";
     9     }
    10@@ -96,11 +97,6 @@ static bool g_generated_cookie = false;
    11 
    12 bool GenerateAuthCookie(std::string* cookie_out, std::optional<fs::perms> cookie_perms)
    13 {
    14-    if (gArgs.IsArgNegated("-rpccookiefile")) {
    15-        LogInfo("RPC authentication cookie file generation is disabled.");
    16-        return true;
    17-    }
    18-
    19     const size_t COOKIE_SIZE = 32;
    20     unsigned char rand_pwd[COOKIE_SIZE];
    21     GetRandBytes(rand_pwd);
    22@@ -111,6 +107,11 @@ bool GenerateAuthCookie(std::string* cookie_out, std::optional<fs::perms> cookie
    23      */
    24     std::ofstream file;
    25     fs::path filepath_tmp = GetAuthCookieFile(true);
    26+    if (filepath_tmp.empty()) {
    27+        LogInfo("RPC authentication cookie file generation is disabled.");
    28+        return true;
    29+    }
    30+
    31     file.open(filepath_tmp);
    32     if (!file.is_open()) {
    33         LogInfo("Unable to open cookie authentication file %s for writing\n", fs::PathToString(filepath_tmp));
    

    would make this safer and clearer.


    hodlinator commented at 9:53 pm on November 18, 2024:
    Thanks! Implemented in latest push with some variation.
  23. in src/httprpc.cpp:73 in cf3e4edc80 outdated
    69@@ -70,7 +70,7 @@ class HTTPRPCTimerInterface : public RPCTimerInterface
    70 
    71 
    72 /* Pre-base64-encoded authentication token */
    73-static std::string strRPCUserColonPass;
    74+static std::optional<std::string> strRPCUserColonPass;
    


    ryanofsky commented at 4:37 am on November 15, 2024:

    In commit “args: Support -norpccookiefile” (cf3e4edc803bf950f280b24c5283a2838c86faf6)

    The changes to httprpc.cpp seem too complicated and I don’t think they are safe because now that an empty strRPCUserColonPass string is allowed by RPCAuthorized, the TimingResistantEqual function can return true when the client provides an empty auth string.

    I also think changing strRPCUserColonPass to std::optional makes state more complicated and code more confusing to think about, even as it weakens the “belt and suspenders” check it is trying to preserve by intializing the variable at the top of the InitRPCAuthentication function and leaving it set even when the function fails.

    To fix these issue, I would leave strRPCUserColonPass as std::string instead of making it into a std::optional, leave the InitRPCAuthentication function unchanged, and just change the RPCAuthorized function as follows:

     0--- a/src/httprpc.cpp
     1+++ b/src/httprpc.cpp
     2@@ -134,8 +134,6 @@ static bool multiUserAuthorized(std::string strUserPass)
     3 
     4 static bool RPCAuthorized(const std::string& strAuth, std::string& strAuthUsernameOut)
     5 {
     6-    if (strRPCUserColonPass.empty()) // Belt-and-suspenders measure if InitRPCAuthentication was not called
     7-        return false;
     8     if (strAuth.substr(0, 6) != "Basic ")
     9         return false;
    10     std::string_view strUserPass64 = TrimStringView(std::string_view{strAuth}.substr(6));
    11@@ -148,7 +146,8 @@ static bool RPCAuthorized(const std::string& strAuth, std::string& strAuthUserna
    12         strAuthUsernameOut = strUserPass.substr(0, strUserPass.find(':'));
    13 
    14     //Check if authorized under single-user field
    15-    if (TimingResistantEqual(strUserPass, strRPCUserColonPass)) {
    16+    // strRPCUserColonPass is empty when -norpccookiefile is specified
    17+    if (!strRPCUserColonPass.empty() && TimingResistantEqual(strUserPass, strRPCUserColonPass)) {
    18         return true;
    19     }
    20     return multiUserAuthorized(strUserPass);
    

    I don’t think it is worth complicating the code so much just to support keeping a belt and suspender check that is no longer valid now that strRPCUserColonPass being empty is a valid state.


    hodlinator commented at 9:55 pm on November 18, 2024:
    Thanks for catching this. Was not my intention to leave the door wide open when users pass -norpccookiefile. :man_facepalming: Kept a belt & suspenders bool in latest push.
  24. in src/common/config.cpp:136 in 77c8a538b7 outdated
    128@@ -129,9 +129,11 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
    129 
    130     const auto conf_path{GetConfigFilePath()};
    131     std::ifstream stream{conf_path};
    


    ryanofsky commented at 4:55 am on November 15, 2024:

    In commit “args: Properly support -noconf and catch directories” (77c8a538b7164f8b65576600eb4668ac160f6b14)

    It doesn’t seem good to try to open a file with an empty path. This behavior doesn’t seem well defined and the call will unnecessarily be passed down to the os when it shouldn’t be. I think it would also clarify the code and avoid the need to add a second IsArgNegated call if this checked for an empty path. Would suggest:

     0    const auto conf_path{GetConfigFilePath()};
     1    std::ifstream stream;
     2    if (!conf_path.empty()) { // path is empty when -noconf is specified
     3        stream = std::ifstream{conf_path};
     4        // Calling peek() on ifstreams opened on directories flags them as !good().
     5        (void)stream.peek();
     6
     7        // not ok to have a config file specified that cannot be opened
     8        if (IsArgSet("-conf") && !stream.good()) {
     9            error = strprintf("specified config file \"%s\" could not be opened.", fs::PathToString(conf_path));
    10            return false;
    11        }
    12    }
    

    hodlinator commented at 9:57 pm on November 18, 2024:
    Fixed in latest push. Also switched from ifstream::peek() to fs::is_directory() after verifying the latter returns true for directory-symlinks as well.
  25. ryanofsky commented at 5:10 am on November 15, 2024: contributor

    Code review 77c8a538b7164f8b65576600eb4668ac160f6b14. Thanks for the updates! This all looks great, my only substantial comments are about the RPC commit which I think is more complicated than it needs to be and may have a bug where it may allow an empty auth string to be accepted if -norpccookiefile is specified, or if there is an initialization failure.

    It may be nice to add python functional tests to exercise some of the new behaviors. It would be nontrivial work to add test coverage for all of these behaviors, but it doesn’t have to be all-or-nothing. Just having some new end-to-end tests of argument parsing edge cases would be a nice improvement to our existing test coverage.

  26. hodlinator force-pushed on Nov 15, 2024
  27. hodlinator force-pushed on Nov 15, 2024
  28. hodlinator force-pushed on Nov 15, 2024
  29. hodlinator marked this as a draft on Nov 15, 2024
  30. hodlinator force-pushed on Nov 18, 2024
  31. hodlinator commented at 10:01 pm on November 18, 2024: contributor

    Thanks for continued review and reminding me to raise the bar for the PR @ryanofsky.

    Added tests which helped uncover that bitcoin-cli might as well also support -norpccookiefile too, and part of src/common/init.cpp which was not handling -noconf correctly.

  32. doc args: Document narrow scope of -color e8a2054edc
  33. hodlinator force-pushed on Nov 18, 2024
  34. hodlinator force-pushed on Nov 18, 2024
  35. DrahtBot added the label CI failed on Nov 18, 2024
  36. DrahtBot commented at 10:36 pm on November 18, 2024: contributor

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

    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.

  37. DrahtBot removed the label Needs rebase on Nov 18, 2024
  38. DrahtBot removed the label CI failed on Nov 18, 2024
  39. hodlinator force-pushed on Nov 19, 2024
  40. l0rinc commented at 11:33 am on November 19, 2024: contributor
    I’d like to review this, but first, I’d like to understand why it is still in draft form.
  41. hodlinator marked this as ready for review on Nov 19, 2024
  42. hodlinator commented at 11:45 am on November 19, 2024: contributor

    I’d like to review this, but first, I’d like to understand why it is still in draft form.

    Had a linefeed issue on Windows in the previous push (and was in a WIP state over the weekend, before that).. but pretty sure it’s ready to go.

  43. in src/bitcoin-cli.cpp:97 in e8a2054edc outdated
    93@@ -94,7 +94,7 @@ static void SetupCliArgs(ArgsManager& argsman)
    94     argsman.AddArg("-netinfo", strprintf("Get network peer connection information from the remote server. An optional argument from 0 to %d can be passed for different peers listings (default: 0). If a non-zero value is passed, an additional \"outonly\" (or \"o\") argument can be passed to see outbound peers only. Pass \"help\" (or \"h\") for detailed help documentation.", NETINFO_MAX_LEVEL), ArgsManager::ALLOW_ANY, OptionsCategory::CLI_COMMANDS);
    95 
    96     SetupChainParamsBaseOptions(argsman);
    97-    argsman.AddArg("-color=<when>", strprintf("Color setting for CLI output (default: %s). Valid values: always, auto (add color codes when standard output is connected to a terminal and OS is not WIN32), never.", DEFAULT_COLOR_SETTING), ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS);
    98+    argsman.AddArg("-color=<when>", strprintf("Color setting for CLI output (default: %s). Valid values: always, auto (add color codes when standard output is connected to a terminal and OS is not WIN32), never. Only applies to the output of -getinfo.", DEFAULT_COLOR_SETTING), ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS);
    


    l0rinc commented at 5:24 pm on November 20, 2024:

    slightly unrelated: Checking the different options, it’s not always trivial to assess what negation would mean, but

    0    if (gArgs.IsArgSet("-color")) {
    1        const std::string color{gArgs.GetArg("-color", DEFAULT_COLOR_SETTING)};
    2        if (color == "always") {
    3            should_colorize = true;
    4        } else if (color == "never") {
    5            should_colorize = false;
    6        } else if (color != "auto") {
    7            throw std::runtime_error("Invalid value for -color option. Valid values: always, auto, never.");
    8        }
    9    }
    

    Indicated that a -nocolor == -color=never could make sense. Or is the ArgsManager::DISALLOW_NEGATION meant to discourage people from requesting that :D?


    hodlinator commented at 9:51 pm on November 20, 2024:

    Or is the ArgsManager::DISALLOW_NEGATION meant to discourage people from requesting that :D?

    Indeed, although I agree with -nocolor potentially equaling -color=never, it is flagged as forbidden and therefore the process is stopped before reaching the quoted code. I’m a bit hesitant to overrule the prior intent of disallowing it.

  44. in src/bitcoin-cli.cpp:1 in f02c4c020c outdated


    l0rinc commented at 5:37 pm on November 20, 2024:

    in scripted-diff: Avoid printing version information for -noversion:

    Nit: the replacement doesn’t need any escapes, if you edit again, consider simplifying:

    0-BEGIN VERIFY SCRIPT-
    1sed -i --regexp-extended 's/\b(gArgs|args)\.IsArgSet\("-version"\)/\1.GetBoolArg("-version", false)/g' $(git grep -l '-version')
    2-END VERIFY SCRIPT-
    

    l0rinc commented at 6:11 pm on November 20, 2024:

    in test: -norpccookiefile:

    What’s the reason for separating the test from the impl? I would understand if this were before the fix (we could check that it reproduces the desired behavior and fails - but we can’t do that here since all tests should fail)


    l0rinc commented at 6:12 pm on November 20, 2024:
    nit in args: Properly support -noconf and catch directories - typo in commit message

    l0rinc commented at 6:19 pm on November 20, 2024:

    in test: Add tests for directory in place of config files, -noconf:

    Same as with the other test, I think it belongs with the related modification


    hodlinator commented at 10:19 pm on November 20, 2024:
    I fail to see the typo, mind pointing it out?

    hodlinator commented at 11:01 pm on November 20, 2024:
    I want it to be easy for reviewers to drop the impl commits or re-order and run what is in the test commits to verify that I’m actually fixing issues.

    hodlinator commented at 11:01 pm on November 20, 2024:
  45. in src/bitcoin-tx.cpp:108 in f02c4c020c outdated
    104@@ -105,11 +105,11 @@ static int AppInitRawTx(int argc, char* argv[])
    105 
    106     fCreateBlank = gArgs.GetBoolArg("-create", false);
    107 
    108-    if (argc < 2 || HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
    109+    if (argc < 2 || HelpRequested(gArgs) || gArgs.GetBoolArg("-version", false)) {
    


    l0rinc commented at 5:40 pm on November 20, 2024:
    nit: since we’re using all values later (here and in a few other examples below), we might as well leave this as IsArgSet at the top - it would simplify the PR diff, but make the scripted diff more complicated. Will leave it for you to decide, don’t have strong feelings either way.

    hodlinator commented at 9:58 pm on November 20, 2024:
    IsArgSet would be true when the user passes -noversion, so the if-block would be entered, which is intended to be avoided in this PR.
  46. in src/init.cpp:488 in 4ccc53aff7 outdated
    482@@ -483,7 +483,7 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)
    483     argsman.AddArg("-blocksonly", strprintf("Whether to reject transactions from network peers. Disables automatic broadcast and rebroadcast of transactions, unless the source peer has the 'forcerelay' permission. RPC transactions are not affected. (default: %u)", DEFAULT_BLOCKSONLY), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
    484     argsman.AddArg("-coinstatsindex", strprintf("Maintain coinstats index used by the gettxoutsetinfo RPC (default: %u)", DEFAULT_COINSTATSINDEX), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
    485     argsman.AddArg("-conf=<file>", strprintf("Specify path to read-only configuration file. Relative paths will be prefixed by datadir location (only useable from command line, not configuration file) (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
    486-    argsman.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
    487+    argsman.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, OptionsCategory::OPTIONS);
    


    l0rinc commented at 5:49 pm on November 20, 2024:
    Do these same arguments apply to blocksdir & walletdir?

    hodlinator commented at 10:31 pm on November 20, 2024:

    Potentially yes, but I’m trying to keep the scope of the PR to the args I discovered here: #16545#pullrequestreview-2316714013

    Open to exploring it in a follow-up!

  47. in src/httprpc.cpp:304 in 80fcd0473a outdated
    302         auto cookie_perms_arg{gArgs.GetArg("-rpccookieperms")};
    303         if (cookie_perms_arg) {
    304             auto perm_opt = InterpretPermString(*cookie_perms_arg);
    305             if (!perm_opt) {
    306-                LogInfo("Invalid -rpccookieperms=%s; must be one of 'owner', 'group', or 'all'.\n", *cookie_perms_arg);
    307+                LogError("Invalid -rpccookieperms=%s; must be one of 'owner', 'group', or 'all'.\n", *cookie_perms_arg);
    


    l0rinc commented at 5:57 pm on November 20, 2024:
    Since you edit these already, could you please check if the trailing newline is still needed?
  48. in src/httprpc.cpp:152 in 80fcd0473a outdated
    148@@ -148,7 +149,8 @@ static bool RPCAuthorized(const std::string& strAuth, std::string& strAuthUserna
    149         strAuthUsernameOut = strUserPass.substr(0, strUserPass.find(':'));
    150 
    151     //Check if authorized under single-user field
    152-    if (TimingResistantEqual(strUserPass, strRPCUserColonPass)) {
    153+    // strRPCUserColonPass is empty when -norpccookiefile is specified
    


    l0rinc commented at 5:59 pm on November 20, 2024:
    super-nit: formatting seems a bit off (whitespace and missing trailing full stop in first line)

    hodlinator commented at 10:58 pm on November 20, 2024:
    Yeah, was itching to do that too, thanks for a second vote. :)
  49. in src/httprpc.cpp:310 in 80fcd0473a outdated
    310             cookie_perms = *perm_opt;
    311         }
    312 
    313-        if (!GenerateAuthCookie(&strRPCUserColonPass, cookie_perms)) {
    314-            return false;
    315+        if (std::optional<bool> result{GenerateAuthCookie(&strRPCUserColonPass, cookie_perms)}) {
    


    l0rinc commented at 6:03 pm on November 20, 2024:

    You gotta’ love these 3-state-booleans :)

    nit: To reduce the noise, consider simplified to either

    0        if (std::optional result{GenerateAuthCookie(&strRPCUserColonPass, cookie_perms)}) {
    

    or

    0        if (auto result{GenerateAuthCookie(&strRPCUserColonPass, cookie_perms)}) {
    

    hodlinator commented at 10:34 pm on November 20, 2024:
    I prefer documenting the type.
  50. in src/httprpc.cpp:321 in 80fcd0473a outdated
    321+            }
    322+        } else {
    323+            LogInfo("RPC authentication cookie file generation is disabled.");
    324         }
    325     } else {
    326         LogPrintf("Config options rpcuser and rpcpassword will soon be deprecated. Locally-run instances may remove rpcuser to use cookie-based auth, or may be replaced with rpcauth. Please see share/rpcauth for rpcauth auth generation.\n");
    


    l0rinc commented at 6:05 pm on November 20, 2024:
    this seems like a slight behavior change: previously when GenerateAuthCookie returned true, this was logged, now it seems to me it may not be (haven’t tried the code)

    hodlinator commented at 10:45 pm on November 20, 2024:

    You mean

    0LogInfo("Using random cookie authentication.\n");
    

    was run independently of whether GenerateAuthCookie returned true or false, but now it may not be? It seemed wrong to me so I made it only happen when the cookie was actually generated.

    If you mean that

    0LogPrintf("Config options rpcuser and rpcpassword will soon be deprecated. Locally-run instances may remove rpcuser to use cookie-based auth, or may be replaced with rpcauth. Please see share/rpcauth for rpcauth auth generation.\n");
    

    was emitted when GenerateAuthCookie was true, I think you may be mixing up some braces/indentation.

  51. in test/functional/interface_bitcoin_cli.py:168 in d412946cc2 outdated
    163@@ -164,6 +164,9 @@ def run_test(self):
    164         self.log.info("Test connecting with non-existing RPC cookie file")
    165         assert_raises_process_error(1, "Could not locate RPC credentials", self.nodes[0].cli('-rpccookiefile=does-not-exist', '-rpcpassword=').echo)
    166 
    167+        self.log.info("Test connecting without RPC cookie file and with password arg")
    168+        assert_equal(BLOCKS, self.nodes[0].cli('-norpccookiefile', '-rpcuser=' + user, '-rpcpassword=' + password).getblockcount())
    


    l0rinc commented at 6:08 pm on November 20, 2024:

    nit: we might as well use f-strings here:

    0        assert_equal(BLOCKS, self.nodes[0].cli('-norpccookiefile', f'-rpcuser={user}', f'-rpcpassword={password}').getblockcount())
    
  52. in test/functional/rpc_users.py:135 in d412946cc2 outdated
    130+
    131+        self.log.info('Starting with -norpccookiefile')
    132+        # Start, but don't wait for RPC connection as TestNode.wait_for_rpc_connection() requires the cookie.
    133+        with self.nodes[0].busy_wait_for_debug_log([b'init message: Done loading']):
    134+            # Pass -rpccookieperms for bonus code coverage of warning
    135+            self.nodes[0].start(extra_args=[f"-norpccookiefile", "-rpccookieperms=owner"])
    


    l0rinc commented at 6:09 pm on November 20, 2024:

    nit: we don’t actually need f-string here:

    0            self.nodes[0].start(extra_args=["-norpccookiefile", "-rpccookieperms=owner"])
    
  53. in src/common/config.cpp:140 in 1607d8d1a9 outdated
    140 
    141-    // not ok to have a config file specified that cannot be opened
    142-    if (IsArgSet("-conf") && !stream.good()) {
    143-        error = strprintf("specified config file \"%s\" could not be opened.", fs::PathToString(conf_path));
    144-        return false;
    145+        // not ok to have a config file specified that cannot be opened
    


    l0rinc commented at 6:15 pm on November 20, 2024:

    nit: double negation makes it more complicated than need be. If you insist on having a comment:

    0        // Config file must be accessible
    

    hodlinator commented at 11:08 pm on November 20, 2024:

    Good point about double negation. Changed to:

    0// If the file is explicitly specified, it must be readable
    

    since the distinction is important.

  54. in src/init/common.cpp:129 in 1607d8d1a9 outdated
    124@@ -125,8 +125,10 @@ bool StartLogging(const ArgsManager& args)
    125     if (fs::exists(config_file_path)) {
    126         LogPrintf("Config file: %s\n", fs::PathToString(config_file_path));
    127     } else if (args.IsArgSet("-conf")) {
    128-        // Warn if no conf file exists at path provided by user
    129-        InitWarning(strprintf(_("The specified config file %s does not exist"), fs::PathToString(config_file_path)));
    130+        if (!args.IsArgNegated("-conf")) {
    131+            // Warn if no conf file exists at path provided by user
    


    l0rinc commented at 6:18 pm on November 20, 2024:
    not sure what this comments adds that the code doesn’t already explain
  55. l0rinc commented at 6:25 pm on November 20, 2024: contributor
    I love that you search for these inconsistencies and attack them head on. +1 for adding representative tests (which I didn’t review in detail yet, will do in the next round of reviews).
  56. scripted-diff: Avoid printing version information for -noversion
    -BEGIN VERIFY SCRIPT-
    sed -i --regexp-extended 's/\b(gArgs|args)\.IsArgSet\("-version"\)/\1.GetBoolArg("-version", false)/g' $(git grep -l '-version')
    -END VERIFY SCRIPT-
    6ff9662760
  57. args: Disallow -nodatadir
    Does not make sense to run without a datadir.
    
    Prior to this change it would be interpreted as a mix of unset and as a relative path of "0".
    12f8d848fd
  58. args: Support -nopid bffd92f00f
  59. args: Support -norpccookiefile for bitcoind and bitcoin-cli
    Now uses separate boolean in place of strRPCUserColonPass to track initialization HTTP RPC authentication.
    21bc3a3657
  60. test: -norpccookiefile
    Both bitcoind and bitcoin-cli.
    8639cf66c8
  61. hodlinator force-pushed on Nov 20, 2024
  62. args: Properly support -noconf and catch directories
    Previously passing a directory path as -conf would lead to an ifstream being opened for it, and would not trigger any errors.
    
    -noconf would previously lead to an ifstream "successfully" being opened to the ".bitcoin"-directory (not a file)). With the change to AbsPathForConfigVal we will now try to open the marginally more correct absolute path "".
    
    Other users of AbsPathForConfigVal() have been updated to handle negation in 2 previous commits.
    879a8d3a68
  63. test: Add tests for directory in place of config files, -noconf 2bf7e59776
  64. hodlinator force-pushed on Nov 20, 2024

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 09:12 UTC

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