-
Notifications
You must be signed in to change notification settings - Fork 73
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
Listen on multiple addresses for net_plugin p2p. #1411
Conversation
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 change prevents disabling p2p listen endpoint, is there some way we can maintain that ability?
plugins/net_plugin/net_plugin.cpp
Outdated
p2p_address = options.at( "p2p-listen-endpoint" ).as<string>(); | ||
EOS_ASSERT( p2p_address.length() <= max_p2p_address_length, chain::plugin_config_exception, | ||
"p2p-listen-endpoint too long, must be less than ${m}", ("m", max_p2p_address_length) ); | ||
if( options.count( "p2p-listen-endpoint" ) && !options.at("p2p-listen-endpoint").as<vector<string>>().empty() && options.at("p2p-listen-endpoint").as<vector<string>>()[0].length()) { |
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 thinks && !options.at("p2p-listen-endpoint").as<vector<string>>()[0].empty()
is easier to understand.
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 think we can remove vector checks at all. code below should perfectly handle empty vector. Or you can add a check later if vector is empty - looks more succinct, easier to understand and more optimal since you do not construct vector multiple times
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'd like to retain the checks in case the default value is ever removed. I figured it was ok to reconstruct the vector because this is startup code executed only once and it would be very unusual for the vector size to exceed even 10 elements.
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.
my main point was having concise and easy to read code at first. I agree that performance could be neglected here if it adds readability or simplicity.
So if you remove it or at least split that huge if
statement - that will improve readability.
technically I do not see any difference in functionality if you'll leave it like that:
if( options.count( "p2p-listen-endpoint" ) ) {
}
in that case p2p_addresses
will be empty anyways and sort
/erase
won't crash on empty vector. If I missed something you could just split the if
like that:
if( options.count( "p2p-listen-endpoint" ) ) {
auto p2ps = options.at( "p2p-listen-endpoint" ).as<vector<string>>();
if (!p2ps.empty() && !p2ps.front().empty()) {
p2p_addresses = p2ps;
/*...*/
}
}
I'm not hard on this, just trying to keep code reasonably simple. net_plugin
code is complicated enough already.
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.
Updated for readability.
|
||
if( !p2p_address.empty() ) { | ||
auto [host, port] = fc::split_host_port(listen_address); | ||
std::transform(p2p_addresses.begin(), p2p_addresses.end(), p2p_server_addresses.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.
I know you do a resize
above, but an assert that these are the same size would be good.
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.
- it looks better to move line 3991 just above that one.
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.
Added assert.
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.
@dimas1185 I'm sorry, the line numbers have moved around too much. I'm not sure what you mean.
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.
@jgiszczak you can skip it. assert looks good.
I meant this one:
`p2p_server_addresses.resize(p2p_addresses.size()); // extend with empty entries as needed`
Outbound connections are always attributed to the first listen address.
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.
please add unit and/or integration test where you check behavior for multiple endpoints specified
Erase undefined elements from p2p_addresses vector after std::unique(). Add assert before std::transform of two vectors. Const correctness and whitespace cleanup.
@@ -182,7 +182,7 @@ class bp_connection_manager { | |||
|
|||
fc_dlog(self()->get_logger(), "pending_downstream_neighbors: ${pending_downstream_neighbors}", | |||
("pending_downstream_neighbors", to_string(pending_downstream_neighbors))); | |||
for (auto neighbor : pending_downstream_neighbors) { self()->connections.connect(config.bp_peer_addresses[neighbor]); } | |||
for (auto neighbor : pending_downstream_neighbors) { self()->connections.connect(config.bp_peer_addresses[neighbor], *self()->p2p_addresses.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.
As discussed please update help and PR description indicating that the first configured server_address is reported in the handshake message to peers. Also guard against p2p_addresses
being empty here.
@@ -0,0 +1,75 @@ | |||
#!/usr/bin/env python3 |
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 adding the test.
It is a bit confusing, can you add more comments about its actions?
also, now net_plugin
's options p2p-listen-endpoint
and p2p-server-address
could be a vector. So I think we should have a test where you specify multiple entries and ensure those are used appropriately.
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.
Comments added and text expanded to multiple ports and to test the --p2p-server-address
parameter better as well.
Exercise multiple listen endpoints, with overrides, in p2p test.
Add network topology diagrams to p2p_multiple_listen_test.
[Group: "P2P Enhancements"] |
This PR allows net_plugin to listen on multiple address:port pairs.
--p2p-listen-endpoint
may now be specified multiple times. Duplicates are ignored.--p2p-server-address
may now be specified multiple times. It may be specified no more times than the number of p2p listen endpoints. Each p2p listen endpoint will be assigned a p2p-server-address in order until the list is exhausted. Listen endpoints with no corresponding p2p-server-address will use their listen address and port as usual. For outgoing connections, the first p2p-server-address will be used as the peer address in handshakes. If not specified, the first listen endpoint will be used.This feature enables differing firewall rules per port, allowing the ability to distinguish between internal cluster peers, other producer peers, and general public peers, as well as any other categories which may be useful.
Documentation Updates
This PR adds the following fields to the results of the
connections
API innet_api_plugin
:The first two are strings. The rest are boolean values.