These have been accumulating over the past few years.
Each is described in its commit message.
These have been accumulating over the past few years.
Each is described in its commit message.
<!--e57a25ab6845829454e8d69fc972939a-->
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
<!--006a51241073e994b41acfe9ec718e94-->
For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/31887.
<!--021abf342d371248e50ceaed478a90ca-->
See the guideline for information on the review process.
| Type | Reviewers |
|---|---|
| ACK | pablomartin4btc, hodlinator, l0rinc, ryanofsky |
| Concept ACK | yancyribbens |
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.
<!--174a7506f384e20aa4161008e828411d-->
Reviewers, this pull request conflicts with the following ones:
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.
As the pull title is "CLI cleanups", just a random comment: It seems odd to treat -getinfo different than -netinfo (and everything else). It would be good for consistency to treat them the same:
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index defe5e4c4e..18bd6b1f91 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -1267,7 +1267,7 @@ static int CommandLineRPC(int argc, char *argv[])
gArgs.CheckMultipleCLIArgs();
std::unique_ptr<BaseRequestHandler> rh;
std::string method;
- if (gArgs.IsArgSet("-getinfo")) {
+ if (gArgs.GetBoolArg("-getinfo", false)) {
rh.reset(new GetinfoRequestHandler());
} else if (gArgs.GetBoolArg("-netinfo", false)) {
if (!args.empty() && (args.at(0) == "h" || args.at(0) == "help")) {
Unrelated, negation probably does not make sense for any of them, so ArgsManager::DISALLOW_NEGATION could be set.
But up to you. Feel free to ignore.
re: #31887 (review)
Mostly agree with this suggestion. It would be nice to remove this IsArgSet call (in a separate commit or PR), because like many other IsArgSet calls, this one introduces a bug and doesn't handle negation properly. A common sense interpretation of -nogetinfo would be to not run the getinfo command instead of running it.
Only part of suggestion above I'd disagree with is the part about also adding the DISALLOW_NEGATION flag. I think the DISALLOW_NEGATION flag is useful for non-boolean options accepting string/int/path/list values where not having a value isn't supported or doesn't make sense (e.g. -nodatadir). For other options, it is better IMO to stay consistent and allow negation so code does not fill up with special cases and users do not have to guess which options allow negation and which will trigger errors for no particular reason.
It would be nice to remove this IsArgSet call (in a separate commit or PR)
Looks like that was followed up on already? https://github.com/bitcoin/bitcoin/pull/31896
It seems odd to treat -getinfo different than -netinfo (and everything else). It would be good for consistency to treat them the same
It would be nice to remove this IsArgSet call (in a separate commit or PR), because like #30529 https://github.com/bitcoin/bitcoin/pull/31212 IsArgSet calls, this one introduces a bug and doesn't handle negation properly. A common sense interpretation of -nogetinfo would be to not run the getinfo command instead of running it.
Thanks, done.
129 | @@ -130,14 +130,11 @@ static void libevent_log_cb(int severity, const char *msg) 130 | // Exception thrown on connection error. This error is used to determine 131 | // when to wait if -rpcwait is given. 132 | // 133 | -class CConnectionFailed : public std::runtime_error 134 | +struct CConnectionFailed : std::runtime_error
Weird to change inheritance from class -> class to struct -> class.
Thanks for having a look! Replied below in #31887 (review).
I consider mixing class/struct in the inheritance hierarchy to be a separate issue.
See https://stackoverflow.com/questions/3574040/c-can-a-struct-inherit-from-a-class in addition to my response above.
My objection does not come from a knowledge gap in what C++ can and cannot do. It is about sticking to certain conventions.
As I was checking to see if the Core Guidelines had influenced me in the matter I only found weak counter evidence:
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c122-use-abstract-classes-as-interfaces-when-complete-separation-of-interface-and-implementation-is-needed
In the example code class D1 inherits from struct Device, full of virtual methods.
I believe I already addressed the conventions comment with #31887 (review).
Thread #31887 (review):
I still read #31887 (review) as what can be done technically, not what should be done (convention). What comes close to indicating convention is the SO-link which shows that some random guy on the internet also prioritizes default visibility over other conventions. His example of taking a struct from a C library and inheriting from it into a class is far from convincing to me - it goes against Core Guidelines: "Do not use inheritance when simply having a data member will do." The way you use inheritance is better than his example in this aspect.
Yes, here it seems cleaner, fitting the use case and requiring less code to do the same thing. I appreciate your indulgence here. Edit: and that commit looks even cleaner now after taking your formatting suggestion.
263 | @@ -267,21 +264,19 @@ static int8_t NetworkStringToId(const std::string& str) 264 | return UNKNOWN_NETWORK; 265 | } 266 | 267 | -/** Class that handles the conversion from a command-line to a JSON-RPC request, 268 | +/** Handle the conversion from a command-line to a JSON-RPC request, 269 | * as well as converting back to a JSON object that can be shown as result. 270 | */ 271 | -class BaseRequestHandler 272 | +struct BaseRequestHandler
Makes more sense to use classes for these as they use virtual functions. Not worth changing just to be able to remove public IMO.
If I'm understanding the feedback, it comes from the idea of C structs being for POD. My understanding is that in C++, classes and structs are identical except for their default inheritance and member access levels, and for the cases here, structs seem to be the appropriate choice that allows simpler code. See also https://stackoverflow.com/a/46339933. I don't mind dropping this change if there is a compelling reason that I'm not aware of, though.
If I'm understanding the feedback, it comes from the idea of C structs being for POD. My understanding is that in C++, classes and structs are identical except for their default inheritance and member access levels, and for the cases here, structs seem to be the appropriate choice that allows simpler code.
I agree that C++ classes and structs are essentially the same, no confusion there. (C# disallows inheritance for struct but not class, Rust doesn't allow inheritance, period. I know we're in C++, but still aware of the tendencies).
What contributed to giving me a sense that this project attempts to use struct/class as a shorthand for distinct things (like POD/vs non-POD), beyond the code that passed me by so far, was dev-notes.md:
I want to maintain a fairly equal bar for review and 3252f3bab02605129a568112f650ef3cb29703b7 (the topic of this thread) stands out to me as having been shot down instantly if done by a relative newcomer. I've benefited from your review guide and am sure you've provided and provide much value to the project.
I really hope I can build a reputation for other things than nits. :)
If you insist on keeping structs, maybe hoist up the braces to conform with the dev-notes? Also, you have inconsistent spacing:
struct AddrinfoRequestHandler : BaseRequestHandler vs
struct GetinfoRequestHandler: BaseRequestHandler
re: #31887 (review)
If you insist on keeping structs, maybe hoist up the braces to conform with the dev-notes?
Not important but do agree it would be good to use recommended style for structs with opening brace on the same line (can just run clang-format).
Also agree classes make more sense than structs here. Compilers may not care about the difference but they mean different things to developers. Structs usually provide data definitions while classes provide interface definitions, so they have different uses and follow different conventions. In this case, I can see the appeal of dropping some lines of code though so don't have a strong opinion.
hoist up the braces to conform with the dev-notes? Also...inconsistent spacing
it would be good to use recommended style (can just run
clang-format)
Good idea, done.
Code reviewed 3252f3bab02605129a568112f650ef3cb29703b7
ACK 9184ec9e8ea6efd4d0d3625a06f223156f940243
Advise dropping 3rd commit, the others seem good.
Code review ACK 3252f3bab02605129a568112f650ef3cb29703b7. All changes look good. No real opinion on the third commit, seems fine to keep or drop
403 | @@ -404,7 +404,7 @@ class NetinfoRequestHandler : public BaseRequestHandler 404 | return UNKNOWN_NETWORK; 405 | } 406 | uint8_t m_details_level{0}; //!< Optional user-supplied arg to set dashboard details level 407 | - bool DetailsRequested() const { return m_details_level > 0 && m_details_level < 5; }
The upper bound check is no longer needed after the merge of PR 21192.
Nit, looks like the bound check is for upper and lower bounds (above zero and bellow 5).
Thank you for taking a look! m_details_level is capped at a maximum value of 4 since https://github.com/bitcoin/bitcoin/pull/21192/files; that line is currently m_details_level = std::min(n, NETINFO_MAX_LEVEL);
I think you misunderstood my comment (or I am not understanding yours). min provides both an upper an lower bound here, so it's just bounded. In the commit you say "upper bound" but I'm saying it should just read "bound".
Oh ok, updated the commit message per s/upper bound/bound/ as you suggested.
cr ACK ccc34a26170ef8c63a6f211eda4464e954873e89
Regarding the 3rd commit:
class outside CLI if we want to be consistent (and if we think we won't require encapsulation for them).*RequestHandler, are we sure the internal representation of these objects and what they expose won't change at any time in the future? It looks like it should be ok, but I'm not too sure if at some point we would need to.1251 | @@ -1252,7 +1252,7 @@ static int CommandLineRPC(int argc, char *argv[]) 1252 | gArgs.CheckMultipleCLIArgs(); 1253 | std::unique_ptr<BaseRequestHandler> rh; 1254 | std::string method; 1255 | - if (gArgs.IsArgSet("-getinfo")) { 1256 | + if (gArgs.GetBoolArg("-getinfo", false)) {
In commit "cli, refactor: for -getinfo, replace IsArgSet() with GetBoolArg()" (ccc34a26170ef8c63a6f211eda4464e954873e89)
Would be good to drop "refactor" from commit subject since this is a small change in behavior, not a pure refactoring. It could be described as a bugfix: no longer treating -nogetinfo and -getinfo=0 the same as -getinfo and -getinfo=1, instead treating them like getinfo was not specified.
Thank you for clarifying the change. Done.
This is a surprising change, the PR states this is a refactor - I would prefer doing this separately
It was added at the request of multiple reviewers and doesn't seem worth splitting out to another PR for that one line and requiring an additional merge script run. Instead, I've dropped the word "refactor" from the PR title.
Code review ACK ccc34a26170ef8c63a6f211eda4464e954873e89. Since last review just added a commit replacing IsArgSet call. I left some suggestions that could be followed up, but they are not very important.
The bounds check is no longer needed after the merge of PR 21192.
Thank you for reviewing, @pablomartin4btc. I prefer to keep this pull scoped only to this file and not increase the scope, as these changes are local to it and it is a file I know reasonably well since 2019 (the RequestHandler representation hasn't changed over that time period).
and run clang-format on it
for consistency with the other CLI commands (-netinfo, -addrinfo, -generate).
This can be considered a bugfix because IsArgSet() returns whether an arg has
been set even if it has been negated. After this change, we no longer treat
-nogetinfo and -getinfo=0 the same as -getinfo and -getinfo=1, and instead as if
-getinfo was not specified.
Co-authored-by: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz>
Co-authored-by: Ryan Ofsky <ryan@ofsky.org>Thanks for the reviews, everyone. Ran clang-format on the third commit and adjusted a few commit messages per the feedback. Should be trivial to re-ack (thanks!)
re-ACK d423fd9ec83ae323ac29bdc1b677ed8260bd59c4
254 | @@ -259,30 +255,25 @@ static void http_error_cb(enum evhttp_request_error err, void *ctx) 255 | reply->error = err; 256 | } 257 | 258 | -/** Class that handles the conversion from a command-line to a JSON-RPC request, 259 | +static int8_t NetworkStringToId(const std::string& str)
info: The NetworkStringToId() duplication was introduced in db4d2c282afd46709792aaf2d36ffbfc1745b776. Could add a reference in the commit message if you retouch.
Your review comment provides that context (thanks). I wouldn't usually add that to the commit message for the same reason as #31887 (review). In this case, however, where the PR and discussion are locked, maybe it wouldn't add notifications to that PR. Not sure.
392 | - } 393 | - return UNKNOWN_NETWORK; 394 | - } 395 | uint8_t m_details_level{0}; //!< Optional user-supplied arg to set dashboard details level 396 | - bool DetailsRequested() const { return m_details_level > 0 && m_details_level < 5; } 397 | + bool DetailsRequested() const { return m_details_level; }
nit: If you re-touch it might be good to add the missing # to the commit message (for tooling/consistency). Unless "PR <number>" is also a convention for tooling unbeknownst to me.
-PR 21192
+PR [#21192](/bitcoin-bitcoin/21192/)
I omit the # in cases like this, where it isn't really important to link them here, so that GitHub does not add a notification in that PR every time this branch is (re)pushed.
Code review ACK d423fd9ec83ae323ac29bdc1b677ed8260bd59c4
Good to see -getinfo negation behavior fixed. I encountered it when exploring args in #16545#pullrequestreview-2316714013 (in the "Expand/collapse lengthy exploration"-section).
Still think the 3rd commit is out of character compared to my brief experience with this project as it is purely stylistic, but at least the formatting was fixed since my previous review.
403 | @@ -404,7 +404,7 @@ class NetinfoRequestHandler : public BaseRequestHandler 404 | return UNKNOWN_NETWORK; 405 | } 406 | uint8_t m_details_level{0}; //!< Optional user-supplied arg to set dashboard details level 407 | - bool DetailsRequested() const { return m_details_level > 0 && m_details_level < 5; } 408 | + bool DetailsRequested() const { return m_details_level; }
This is better than before, but having a NETINFO_MAX_LEVEL and a checking the bounded values in methods and having DetailsRequested, but also checking it manually in https://github.com/bitcoin/bitcoin/blob/master/src/bitcoin-cli.cpp#L499-L501 where we're checking the raw n value seems quite hacky.
Seems the code is begging for a bounded type - if we're cleaning it up, we might as well try an enum here:
enum class NetinfoDetailLevel : uint8_t {
BASIC = 0,
PEERS,
PEERS_WITH_ADDR,
PEERS_WITH_VER,
FULL
};
where we're checking the raw n value
That is to check user input.
I think the abstraction level here is fine, but happy to review if you propose a further abstraction in a follow-up.
258 | @@ -259,6 +259,14 @@ static void http_error_cb(enum evhttp_request_error err, void *ctx) 259 | reply->error = err; 260 | } 261 | 262 | +static int8_t NetworkStringToId(const std::string& str)
from the usages it seems we can modernize this in a few more ways:
UNKNOWN_NETWORK seems to serve as a value-missing proxy - we could use an optional type insteadconst std::string& could be modernized to static std::optional<int8_t> NetworkStringToId(std::string_view network)This would allow us to change the usages to something like:
if (auto network_id{NetworkStringToId(network_name)}) {
++counts.at(*network_id);
}
Yes, IIRC std::optional wasn't available when this was added, as the codebase was using C++11 at that time. I think this would be more of a modernization rewrite than a cleanup, but happy to review if you want to propose it.
258 | @@ -259,6 +259,14 @@ static void http_error_cb(enum evhttp_request_error err, void *ctx) 259 | reply->error = err; 260 | } 261 | 262 | +static int8_t NetworkStringToId(const std::string& str) 263 | +{ 264 | + for (size_t i = 0; i < NETWORKS.size(); ++i) {
we're returning an int8_t, we might as well iterate over one
for (int8_t i{0}; i < NETWORKS.size(); ++i) {
Not sure but I think this would cause a conversion from size_t to int8_t on each iteration, rather than once for return i. Doesn't seem worth it.
the problem is likely that the method returns int8_t for an index - unnecessary, should likely be size_t or int - not important
That's true about the index being int.
278 | 279 | /** Process addrinfo requests */ 280 | -class AddrinfoRequestHandler : public BaseRequestHandler 281 | -{ 282 | -public: 283 | +struct AddrinfoRequestHandler : BaseRequestHandler {
simple structs are fine, but I'm not a fan of struct inheritance, I like the previous version more in the non-trivial cases
If I'm understanding the comment ("simple structs are fine"), it comes from the idea of structs being for POD, say, in C. In C++, classes and structs are identical except for their default inheritance and member access levels, and for the use cases here, a struct appears to be the more appropriate choice that allows simpler, cleaner code (see also stackoverflow.com/a/46339933. Struct inheritance is also fine (see discussions like stackoverflow.com/questions/3574040/c-can-a-struct-inherit-from-a-class. If there is a technical issue beyond style nits, happy to re-evaluate.
I like these cleanups, ans we should go a step further and modernize the code more when touching them. I'm also not a fan of the 3rd commit for the inheritance cases and would prefer seeing the last commit in a separate PR, doesn't seem like a "refactor:"
I like these cleanups, ans we should go a step further and modernize the code more when touching them. I'm also not a fan of the 3rd commit for the inheritance cases and would prefer seeing the last commit in a separate PR, doesn't seem like a "refactor:"
Thanks for reviewing. The last commit was added at the request of multiple reviewers, but I've removed "refactor" from the pull title. Addressed the other feedback individually and happy to look at any modernization follow-ups you'd like to propose.
I would prefer doing the modernizations here to get rid of more technical debt, but this is already better than before so:
ACK d423fd9ec83ae323ac29bdc1b677ed8260bd59c4
Code review ACK d423fd9ec83ae323ac29bdc1b677ed8260bd59c4, just running clang-format and updating commit messages since last review