-
Notifications
You must be signed in to change notification settings - Fork 253
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Showing Local Addresses in Node Window #626
base: master
Are you sure you want to change the base?
Conversation
I've got this from the linter:
Not sure how I should convert from int to string correctly. Any advice? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
concept ack
full diff:
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 01989b5a0..080f9b979 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -961,15 +961,16 @@ void RPCConsole::updateNetworkState()
ui->numberOfConnections->setText(connections);
// localAddressess
- std::string localAddresses="";
+ QString local_addresses;
LOCK(g_maplocalhost_mutex);
for (const std::pair<const CNetAddr, LocalServiceInfo> &item : mapLocalHost)
- localAddresses += item.first.ToString() + ":" + std::to_string(item.second.nPort) + ", ";
- if (localAddresses.length() > 2)
- localAddresses[localAddresses.length()-2] = 0;
+ local_addresses += QString::fromStdString(item.first.ToString()) + ":" + QString::number(item.second.nPort) + ", ";
+ if (local_addresses.length() > 2)
+ local_addresses[local_addresses.length()-2] = 0;
else
- localAddresses = "None";
- ui->localAddresses->setText(QString::fromStdString(localAddresses));
+ //: Signals to the user that they do not have any local addresses.
+ local_addresses = tr("None");
+ ui->localAddresses->setText(local_addresses);
}
c21adfa
to
e3c2e03
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aside from the code comments, there is an important topic to mention:
Let's not access fields from the net layer in a GUI widget/view, the sources architecture is (should be) widget -> model -> interface -> backend.
Better to create the proper flow to access the information that you are looking for:
rpcconsole -> clientModel -> node interface -> net layer.
In this way, the field access is encapsulated, layers responsibilities are respected and the same function can be used, and tested, from other user facing end points like the RPC server equally.
src/qt/rpcconsole.cpp
Outdated
std::string localAddresses=""; | ||
LOCK(g_maplocalhost_mutex); | ||
for (const std::pair<const CNetAddr, LocalServiceInfo> &item : mapLocalHost) | ||
localAddresses += item.first.ToString() + ":" + std::to_string(item.second.nPort) + ", "; | ||
if (localAddresses.length() > 2) | ||
localAddresses[localAddresses.length()-2] = 0; | ||
else | ||
localAddresses = "None"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would suggest to write it differently:
std::string localAddresses=""; | |
LOCK(g_maplocalhost_mutex); | |
for (const std::pair<const CNetAddr, LocalServiceInfo> &item : mapLocalHost) | |
localAddresses += item.first.ToString() + ":" + std::to_string(item.second.nPort) + ", "; | |
if (localAddresses.length() > 2) | |
localAddresses[localAddresses.length()-2] = 0; | |
else | |
localAddresses = "None"; | |
std::string localAddresses = ""; | |
LOCK(g_maplocalhost_mutex); | |
for (auto it = mapLocalHost.begin(); it != mapLocalHost.end();) { | |
localAddresses += it->first.ToString() + ":" + std::to_string(it->second.nPort); | |
if (++it != mapLocalHost.end()) localAddresses += ", "; | |
} | |
if (localAddresses.empty()) localAddresses = "None"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a review on an earlier state of the PR, the following would be the appropriate diff to express your idea:
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 386b9373c..a249d7895 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -964,13 +964,12 @@ void RPCConsole::updateNetworkState()
// localAddressess
QString local_addresses;
LOCK(g_maplocalhost_mutex);
- for (const std::pair<const CNetAddr, LocalServiceInfo> &item : mapLocalHost)
- local_addresses += QString::fromStdString(item.first.ToString()) + ":" + QString::number(item.second.nPort) + ", ";
- if (local_addresses.length() > 2)
- local_addresses[local_addresses.length()-2] = 0;
- else
- // Signals to the user that they do not have any local addresses.
- local_addresses = tr("None");
+ for (auto it = mapLocalHost.begin(); it != mapLocalHost.end();) {
+ local_addresses += QString::fromStdString(it->first.ToString()) + ":" + QString::number(it->second.nPort) + ", ";
+ if (++it != mapLocalHost.end()) local_addresses += ", ";
+ }
+ //: Signals to the user that they do not have any local addresses.
+ if (local_addresses.isEmpty()) local_addresses = tr("None");
ui->localAddresses->setText(local_addresses);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually pointed to the previous state on purpose. My main suggestion was to encapsulate the mutex and mapLocalHost
access in the backend, which is Qt/GUI independent. So cannot use QString from there. Need to craft a plain std::string, then convert it to QString once it passes through the model class or directly in the widget.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dear @furszy thanks for the valuable input. Applied most of them except this encapsulation part. I understand your rational and I think it's a better design. But since the number of connections are also calculated here, I did the same with Local Address.
Since I'm leaving for a 10 day off the grid trip, I submitted a new commit (squashed) with these chagnes:
- removed the extra new line
- used your better loop for ", " additions
- removed unnecessary comments (kept the one from @jarolrod)
Thanks @jarolrod for the inputs and fixes and reviews.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dear @furszy thanks for the valuable input. Applied most of them except this encapsulation part. I understand your rational and I think it's a better design. But since the number of connections are also calculated here, I did the same with Local Address.
The connections aren't calculated here (on the widget, as you are doing for the external addresses). It's encapsulated inside the connections manager. The flow is the following one: widget -> model -> node -> conman.
updateNetworkState
calls clientModel->getNumConnections
which calls the interface node.getNodeCount
, which calls the connection manager.
Let's try to respect the different layers, encapsulating access where is possible, to get cleaner code to work with. (If you need a hand with it, feel very welcome to ping me on IRC)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. Did the flow as you said. Now we are querying layer by layer. Please comment if it still needs improvement. I decided to pass the std::map<CNetAddr, LocalServiceInfo>
to keep it flexible enough for different use cases; for example in this specific usecase (showing IPs in GUI), i was able to do check for "IsI2P" on CNetAddrs.
e3c2e03
to
c47f01b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK
- I agree with showing the Local Address on the Information Tab.
- I successfully compiled the PR on
Ubuntu 22.04
withQt version 5.15.3
. - I was able to verify that the Local Address option is displayed correctly on the Information Tab.
Screenshot:
Currently, I am figuring out how to add local addresses to check if they are displayed correctly. It would be awesome if someone could point towards documentation on how to do so.
@@ -249,6 +249,29 @@ | |||
</widget> | |||
</item> | |||
<item row="9" column="0"> | |||
<widget class="QLabel" name="label_14"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
<widget class="QLabel" name="label_14"> | |
<widget class="QLabel" name="labelLocalAddresses"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for the checks & ACK @shaavan . I kept the label_14 in accordance in most of other fields which had the same pattern.
regarding the listening port, you can test with something like (for testnet):
testnet=1
blocksonly=1
[test]
#prune=1000 # this has no effect during syncing
externalip=100.200.100.10
rpcbind=127.0.0.1
rpcallowip=0.0.0.0/0
rpcuser=user
rpcpassword=pass
as your bitcoin.conf to force a listening IP.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK c47f01b
Continuing on my previous review:
I was able to add local addresses successfully and tested that those were displayed perfectly on the GUI under the Local Address option.
Method of testing:
I added the following options in the bitcoin.conf
file.
[signet]
externalip=100.200.100.11
externalip=100.200.100.10
externalip=100.200.100.12
The IP addresses, along with the port number, appeared in the GUI.
Note: The IP:port
appears in the sorted order irrespective of the order provided in the bitcoin.conf
file. This behavior is the same as the -netinfo
RPC command.
Thanks, @jadijadi, for the help on adding the listening ports!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review ACK c47f01b
Some nits
src/qt/forms/debugwindow.ui
Outdated
@@ -249,6 +249,29 @@ | |||
</widget> | |||
</item> | |||
<item row="9" column="0"> | |||
<widget class="QLabel" name="label_14"> | |||
<property name="text"> | |||
<string>Local Address</string> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could add a translator comment here by adding in the extracomment
field:
<string>Local Address</string> | |
<string extracomment="nice translator comment">Local Address</string> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While here, if there's more than one local address; I guess this should take the plural form, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or could be just changed to "Local Address(es)" maybe?
|
Please rebase due to the conflict with the current master branch (b968424). |
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. ConflictsNo conflicts as of last run. |
Concept ACK Will test on macos x86/Arm64 today |
src/qt/rpcconsole.cpp
Outdated
LOCK(g_maplocalhost_mutex); | ||
for (auto it = mapLocalHost.begin(); it != mapLocalHost.end();) { | ||
local_addresses += QString::fromStdString(it->first.ToString()) + ":" + QString::number(it->second.nPort); | ||
if (++it != mapLocalHost.end()) local_addresses += ", "; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kinda ugly to do the increment here. Maybe make the loop normal, and check for it != mapLocalHost.begin()
at the start of it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed to a normal loop and checking for .begin().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK and tested c47f01b
Thanks @furszy for emphasizing the importance of a good code design and architectural integrity. These principles are crucial for the long-term maintainability and scalability of our project. I totally agree with his code change recommendation in terms of the flow/ pattern to follow.
In terms of the UI itself, I'd use the plural form "Local Addresses", as @jarolrod also pointed it out, to be consistent with the getnetworkinfo
rpc command output.
Concept ACK, kinda works. Minor nit noticed - could avoid adding ":0" as a port for I2P addresses. |
Another thing - list is currently comma separated, without wrapping. Wouldn't it be too long if somebody has IPv4, IPv6, CJDNS, Tor and I2P addresses at the same time? |
This PR still have a couple of unaddressed comments: #626 (comment) and #626 (comment). @jadijadi Are you still working on this? |
Sorry for forgetting this... will check and comment soon |
thanks for the suggestion, did this. |
Thanks for this point, it is fixed and the widget worswraps and extends when needed. |
c47f01b
to
c3b5638
Compare
Dear @hebasto , addressed all issues, updated the code & replied to queries. Thanks for the follow up. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for the encapsulation jadijadi.
src/interfaces/node.h
Outdated
//! Get num blocks. | ||
virtual std::map<CNetAddr, LocalServiceInfo> getLocalAddresses() = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wrong description
src/node/interfaces.cpp
Outdated
std::map<CNetAddr, LocalServiceInfo> empty; | ||
|
||
return m_context->connman ? m_context->connman->getLocalAddresses() : empty; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::map<CNetAddr, LocalServiceInfo> empty; | |
return m_context->connman ? m_context->connman->getLocalAddresses() : empty; | |
return m_context->connman ? m_context->connman->getLocalAddresses() : {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for all the support and patient. Applying them. The {}
was also my first try but I got:
error: initializer list cannot be used on the right hand side of operator ':'
Now I changed it to
if (m_context->connman)
return m_context->connman->getLocalAddresses();
else
return {};
to prevent that ugly empty
variable of mine.
src/qt/rpcconsole.cpp
Outdated
|
||
QString local_addresses; | ||
std::map<CNetAddr, LocalServiceInfo> mapHosts = clientModel->getLocalAddresses(); | ||
for (auto it = mapHosts.begin(); it != mapHosts.end(); it++) { | ||
if (it != mapHosts.begin()) local_addresses += ", "; | ||
if (it->first.IsI2P()) | ||
local_addresses += QString::fromStdString(it->first.ToStringAddr()); | ||
else | ||
local_addresses += QString::fromStdString(it->first.ToStringAddr()) + ":" + QString::number(it->second.nPort); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe?
QString local_addresses;
std::map<CNetAddr, LocalServiceInfo> hosts = clientModel->getLocalAddresses();
for (const auto& [addr, info] : hosts) {
local_addresses += QString::fromStdString(it->first.ToStringAddr());
if (!addr.IsPrivacyNet()) local_addresses += ":" + QString::number(it->second.nPort);
local_addresses += ", ";
}
local_addresses.chop(2); // remove last ", "
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is more beautiful and understandable. Replaced the it->first
& it->second
with addr
& info
:
for (const auto& [addr, info] : hosts) {
local_addresses += QString::fromStdString(addr.ToStringAddr());
if (!addr.IsPrivacyNet()) local_addresses += ":" + QString::number(info.nPort);
local_addresses += ", ";
}
local_addresses.chop(2); // remove last ", "
c3b5638
to
56bdeb2
Compare
src/interfaces/node.h
Outdated
@@ -168,6 +168,9 @@ class Node | |||
//! Get num blocks. | |||
virtual int getNumBlocks() = 0; | |||
|
|||
//! Get local addresses. | |||
virtual std::map<CNetAddr, LocalServiceInfo> getLocalAddresses() = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit
virtual std::map<CNetAddr, LocalServiceInfo> getLocalAddresses() = 0; | |
virtual std::map<CNetAddr, LocalServiceInfo> getNetLocalAddresses() = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with this. Will change because "LocalAddress" can be confusing in BTC context.
src/qt/rpcconsole.cpp
Outdated
std::map<CNetAddr, LocalServiceInfo> hosts = clientModel->getLocalAddresses(); | ||
for (const auto& [addr, info] : hosts) { | ||
local_addresses += QString::fromStdString(addr.ToStringAddr()); | ||
if (!addr.IsPrivacyNet()) local_addresses += ":" + QString::number(info.nPort); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK Tor hidden services do still have port numbers
Also, please split the interfaces changes into a different commit than the GUI changes. |
Might be a good improvement to cherry-pick e4fddc9f395819d0bdf74003676aa563929756fa and use it to update; in testing, I found myself watching for None to change, but it never did because the string isn't updated. |
Contributes to bitcoin-core#564 by providing an interface for mapLocalHost through net -> node interface -> clientModel. Later this value can be read by GUI to show the local addresses.
56bdeb2
to
283c855
Compare
did that. cleaner and atomic. thanks. |
Hmm, it's not that way in your new push tho |
283c855
to
2116e4a
Compare
Ouch... pushed. thanks. |
Somehow you introduced a typo in the commit message >_< |
Adds a new row to the Node Window (debugwindow.ui) under the Network section which shows the LocalAddresses. fixes bitcoin-core#564
2116e4a
to
ea576b6
Compare
Oh.. sorry. fixed and added a spellchecker. |
This change adds a new row to the Node Window (debugwindow.ui)
under the Network section which shows the LocalAddresses.
fixes #564