Group headings for P2P discovery (#3822)

* P2P Discovery Options group

Signed-off-by: Sally MacFarlane <sally.macfarlane@consensys.net>
pull/3830/head
Sally MacFarlane 3 years ago committed by GitHub
parent eb5e604bcd
commit fe8ad2d572
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 310
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java

@ -310,9 +310,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
new MetricCategoryRegistryImpl();
private final MetricCategoryConverter metricCategoryConverter = new MetricCategoryConverter();
// Public IP stored to prevent having to research it each time we need it.
private InetAddress autoDiscoveredDefaultIP = null;
private final PreSynchronizationTaskRunner preSynchronizationTaskRunner =
new PreSynchronizationTaskRunner();
@ -356,96 +353,146 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
description = "Identification for this node in the Client ID",
arity = "1")
private final Optional<String> identityString = Optional.empty();
// P2P Discovery Option Group
@CommandLine.ArgGroup(validate = false, heading = "@|bold P2P Discovery Options|@%n")
P2PDiscoveryOptionGroup p2PDiscoveryOptionGroup = new P2PDiscoveryOptionGroup();
// Completely disables P2P within Besu.
@Option(
names = {"--p2p-enabled"},
description = "Enable P2P functionality (default: ${DEFAULT-VALUE})",
arity = "1")
private final Boolean p2pEnabled = true;
// Boolean option to indicate if peers should NOT be discovered, default to
// false indicates that
// the peers should be discovered by default.
//
// This negative option is required because of the nature of the option that is
// true when
// added on the command line. You can't do --option=false, so false is set as
// default
// and you have not to set the option at all if you want it false.
// This seems to be the only way it works with Picocli.
// Also many other software use the same negative option scheme for false
// defaults
// meaning that it's probably the right way to handle disabling options.
@Option(
names = {"--discovery-enabled"},
description = "Enable P2P discovery (default: ${DEFAULT-VALUE})",
arity = "1")
private final Boolean peerDiscoveryEnabled = true;
static class P2PDiscoveryOptionGroup {
// A list of bootstrap nodes can be passed
// and a hardcoded list will be used otherwise by the Runner.
// NOTE: we have no control over default value here.
@Option(
names = {"--bootnodes"},
paramLabel = "<enode://id@host:port>",
description =
"Comma separated enode URLs for P2P discovery bootstrap. "
+ "Default is a predefined list.",
split = ",",
arity = "0..*")
private final List<String> bootNodes = null;
// Public IP stored to prevent having to research it each time we need it.
private InetAddress autoDiscoveredDefaultIP = null;
@Option(
names = {"--max-peers"},
paramLabel = MANDATORY_INTEGER_FORMAT_HELP,
description = "Maximum P2P connections that can be established (default: ${DEFAULT-VALUE})")
private final Integer maxPeers = DEFAULT_MAX_PEERS;
// Completely disables P2P within Besu.
@Option(
names = {"--p2p-enabled"},
description = "Enable P2P functionality (default: ${DEFAULT-VALUE})",
arity = "1")
private final Boolean p2pEnabled = true;
// Boolean option to indicate if peers should NOT be discovered, default to
// false indicates that
// the peers should be discovered by default.
//
// This negative option is required because of the nature of the option that is
// true when
// added on the command line. You can't do --option=false, so false is set as
// default
// and you have not to set the option at all if you want it false.
// This seems to be the only way it works with Picocli.
// Also many other software use the same negative option scheme for false
// defaults
// meaning that it's probably the right way to handle disabling options.
@Option(
names = {"--discovery-enabled"},
description = "Enable P2P discovery (default: ${DEFAULT-VALUE})",
arity = "1")
private final Boolean peerDiscoveryEnabled = true;
@Option(
names = {"--remote-connections-limit-enabled"},
description =
"Whether to limit the number of P2P connections initiated remotely. (default: ${DEFAULT-VALUE})")
private final Boolean isLimitRemoteWireConnectionsEnabled = true;
// A list of bootstrap nodes can be passed
// and a hardcoded list will be used otherwise by the Runner.
// NOTE: we have no control over default value here.
@Option(
names = {"--bootnodes"},
paramLabel = "<enode://id@host:port>",
description =
"Comma separated enode URLs for P2P discovery bootstrap. "
+ "Default is a predefined list.",
split = ",",
arity = "0..*")
private final List<String> bootNodes = null;
@Option(
names = {"--remote-connections-max-percentage"},
paramLabel = MANDATORY_DOUBLE_FORMAT_HELP,
description =
"The maximum percentage of P2P connections that can be initiated remotely. Must be between 0 and 100 inclusive. (default: ${DEFAULT-VALUE})",
arity = "1",
converter = PercentageConverter.class)
private final Integer maxRemoteConnectionsPercentage =
Fraction.fromFloat(DEFAULT_FRACTION_REMOTE_WIRE_CONNECTIONS_ALLOWED)
.toPercentage()
.getValue();
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@Option(
names = {"--p2p-host"},
paramLabel = MANDATORY_HOST_FORMAT_HELP,
description = "IP address this node advertises to its peers (default: ${DEFAULT-VALUE})",
arity = "1")
private String p2pHost = autoDiscoverDefaultIP().getHostAddress();
@Option(
names = {"--random-peer-priority-enabled"},
description =
"Allow for incoming connections to be prioritized randomly. This will prevent (typically small, stable) networks from forming impenetrable peer cliques. (default: ${DEFAULT-VALUE})")
private final Boolean randomPeerPriority = false;
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@Option(
names = {"--p2p-interface"},
paramLabel = MANDATORY_HOST_FORMAT_HELP,
description =
"The network interface address on which this node listens for P2P communication (default: ${DEFAULT-VALUE})",
arity = "1")
private String p2pInterface = NetworkUtility.INADDR_ANY;
@Option(
names = {"--banned-node-ids", "--banned-node-id"},
paramLabel = MANDATORY_NODE_ID_FORMAT_HELP,
description = "A list of node IDs to ban from the P2P network.",
split = ",",
arity = "1..*")
void setBannedNodeIds(final List<String> values) {
try {
bannedNodeIds =
values.stream()
.filter(value -> !value.isEmpty())
.map(EnodeURLImpl::parseNodeId)
.collect(Collectors.toList());
} catch (final IllegalArgumentException e) {
throw new ParameterException(
commandLine, "Invalid ids supplied to '--banned-node-ids'. " + e.getMessage());
@Option(
names = {"--p2p-port"},
paramLabel = MANDATORY_PORT_FORMAT_HELP,
description = "Port on which to listen for P2P communication (default: ${DEFAULT-VALUE})",
arity = "1")
private final Integer p2pPort = EnodeURLImpl.DEFAULT_LISTENING_PORT;
@Option(
names = {"--max-peers"},
paramLabel = MANDATORY_INTEGER_FORMAT_HELP,
description = "Maximum P2P connections that can be established (default: ${DEFAULT-VALUE})")
private final Integer maxPeers = DEFAULT_MAX_PEERS;
@Option(
names = {"--remote-connections-limit-enabled"},
description =
"Whether to limit the number of P2P connections initiated remotely. (default: ${DEFAULT-VALUE})")
private final Boolean isLimitRemoteWireConnectionsEnabled = true;
@Option(
names = {"--remote-connections-max-percentage"},
paramLabel = MANDATORY_DOUBLE_FORMAT_HELP,
description =
"The maximum percentage of P2P connections that can be initiated remotely. Must be between 0 and 100 inclusive. (default: ${DEFAULT-VALUE})",
arity = "1",
converter = PercentageConverter.class)
private final Integer maxRemoteConnectionsPercentage =
Fraction.fromFloat(DEFAULT_FRACTION_REMOTE_WIRE_CONNECTIONS_ALLOWED)
.toPercentage()
.getValue();
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@CommandLine.Option(
names = {"--discovery-dns-url"},
description = "Specifies the URL to use for DNS discovery")
private String discoveryDnsUrl = null;
@Option(
names = {"--random-peer-priority-enabled"},
description =
"Allow for incoming connections to be prioritized randomly. This will prevent (typically small, stable) networks from forming impenetrable peer cliques. (default: ${DEFAULT-VALUE})")
private final Boolean randomPeerPriority = false;
@Option(
names = {"--banned-node-ids", "--banned-node-id"},
paramLabel = MANDATORY_NODE_ID_FORMAT_HELP,
description = "A list of node IDs to ban from the P2P network.",
split = ",",
arity = "1..*")
void setBannedNodeIds(final List<String> values) {
try {
bannedNodeIds =
values.stream()
.filter(value -> !value.isEmpty())
.map(EnodeURLImpl::parseNodeId)
.collect(Collectors.toList());
} catch (final IllegalArgumentException e) {
throw new ParameterException(
new CommandLine(this),
"Invalid ids supplied to '--banned-node-ids'. " + e.getMessage());
}
}
}
private Collection<Bytes> bannedNodeIds = new ArrayList<>();
private Collection<Bytes> bannedNodeIds = new ArrayList<>();
// Used to discover the default IP of the client.
// Loopback IP is used by default as this is how smokeTests require it to be
// and it's probably a good security behaviour to default only on the localhost.
private InetAddress autoDiscoverDefaultIP() {
autoDiscoveredDefaultIP =
Optional.ofNullable(autoDiscoveredDefaultIP).orElseGet(InetAddress::getLoopbackAddress);
return autoDiscoveredDefaultIP;
}
}
@Option(
names = {"--sync-mode"},
@ -470,30 +517,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
+ " (default: ${DEFAULT-VALUE})")
private final NetworkName network = null;
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@Option(
names = {"--p2p-host"},
paramLabel = MANDATORY_HOST_FORMAT_HELP,
description = "IP address this node advertises to its peers (default: ${DEFAULT-VALUE})",
arity = "1")
private String p2pHost = autoDiscoverDefaultIP().getHostAddress();
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@Option(
names = {"--p2p-interface"},
paramLabel = MANDATORY_HOST_FORMAT_HELP,
description =
"The network interface address on which this node listens for P2P communication (default: ${DEFAULT-VALUE})",
arity = "1")
private String p2pInterface = NetworkUtility.INADDR_ANY;
@Option(
names = {"--p2p-port"},
paramLabel = MANDATORY_PORT_FORMAT_HELP,
description = "Port on which to listen for P2P communication (default: ${DEFAULT-VALUE})",
arity = "1")
private final Integer p2pPort = EnodeURLImpl.DEFAULT_LISTENING_PORT;
@Option(
names = {"--nat-method"},
description =
@ -1141,7 +1164,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
@Option(
names = {"--target-gas-limit"},
description =
"Sets target gas limit per block. If set each block's gas limit will approach this setting over time if the current gas limit is different.")
"Sets target gas limit per block. If set, each block's gas limit will approach this setting over time if the current gas limit is different.")
private final Long targetGasLimit = null;
// Tx Pool Option Group
@ -1263,12 +1286,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
"Specifies the static node file containing the static nodes for this node to connect to")
private final Path staticNodesFile = null;
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@CommandLine.Option(
names = {"--discovery-dns-url"},
description = "Specifies the URL to use for DNS discovery")
private String discoveryDnsUrl = null;
@Mixin private P2PTLSConfigOptions p2pTLSConfigOptions;
@Mixin private PkiBlockCreationOptions pkiBlockCreationOptions;
@ -1572,14 +1589,14 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
private Runner buildRunner() {
return synchronize(
besuController,
p2pEnabled,
p2PDiscoveryOptionGroup.p2pEnabled,
p2pTLSConfiguration,
peerDiscoveryEnabled,
p2PDiscoveryOptionGroup.peerDiscoveryEnabled,
ethNetworkConfig,
maxPeers,
p2pHost,
p2pInterface,
p2pPort,
p2PDiscoveryOptionGroup.maxPeers,
p2PDiscoveryOptionGroup.p2pHost,
p2PDiscoveryOptionGroup.p2pInterface,
p2PDiscoveryOptionGroup.p2pPort,
graphQLConfiguration,
jsonRpcConfiguration,
engineJsonRpcConfiguration,
@ -1687,7 +1704,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
private void validateOptions() {
issueOptionWarnings();
validateP2PInterface(p2pInterface);
validateP2PInterface(p2PDiscoveryOptionGroup.p2pInterface);
validateMiningParams();
validateNatParams();
validateNetStatsParams();
@ -1819,7 +1836,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
logger,
commandLine,
"--p2p-enabled",
!p2pEnabled,
!p2PDiscoveryOptionGroup.p2pEnabled,
asList(
"--bootnodes",
"--discovery-enabled",
@ -2071,7 +2088,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.reorgLoggingThreshold(reorgLoggingThreshold)
.evmConfiguration(unstableEvmOptions.toDomainObject())
.dataStorageConfiguration(dataStorageOptions.toDomainObject())
.maxPeers(maxPeers);
.maxPeers(p2PDiscoveryOptionGroup.maxPeers);
}
private GraphQLConfiguration graphQLConfiguration() {
@ -2086,7 +2103,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
graphQLConfiguration.setEnabled(graphQlOptionGroup.isGraphQLHttpEnabled);
graphQLConfiguration.setHost(
Strings.isNullOrEmpty(graphQlOptionGroup.graphQLHttpHost)
? autoDiscoverDefaultIP().getHostAddress()
? p2PDiscoveryOptionGroup.autoDiscoverDefaultIP().getHostAddress()
: graphQlOptionGroup.graphQLHttpHost);
graphQLConfiguration.setPort(graphQlOptionGroup.graphQLHttpPort);
graphQLConfiguration.setHostsAllowlist(hostsAllowlist);
@ -2160,7 +2177,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
jsonRpcConfiguration.setEnabled(jsonRPCHttpOptionGroup.isRpcHttpEnabled);
jsonRpcConfiguration.setHost(
Strings.isNullOrEmpty(jsonRPCHttpOptionGroup.rpcHttpHost)
? autoDiscoverDefaultIP().getHostAddress()
? p2PDiscoveryOptionGroup.autoDiscoverDefaultIP().getHostAddress()
: jsonRPCHttpOptionGroup.rpcHttpHost);
jsonRpcConfiguration.setPort(listenPort);
jsonRpcConfiguration.setMaxActiveConnections(jsonRPCHttpOptionGroup.rpcHttpMaxConnections);
@ -2363,7 +2380,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
webSocketConfiguration.setEnabled(jsonRPCWebsocketOptionGroup.isRpcWsEnabled);
webSocketConfiguration.setHost(
Strings.isNullOrEmpty(jsonRPCWebsocketOptionGroup.rpcWsHost)
? autoDiscoverDefaultIP().getHostAddress()
? p2PDiscoveryOptionGroup.autoDiscoverDefaultIP().getHostAddress()
: jsonRPCWebsocketOptionGroup.rpcWsHost);
webSocketConfiguration.setPort(listenPort);
webSocketConfiguration.setMaxFrameSize(jsonRPCWebsocketOptionGroup.rpcWsMaxFrameSize);
@ -2425,7 +2442,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.enabled(metricsOptionGroup.isMetricsEnabled)
.host(
Strings.isNullOrEmpty(metricsOptionGroup.metricsHost)
? autoDiscoverDefaultIP().getHostAddress()
? p2PDiscoveryOptionGroup.autoDiscoverDefaultIP().getHostAddress()
: metricsOptionGroup.metricsHost)
.port(metricsOptionGroup.metricsPort)
.protocol(metricsOptionGroup.metricsProtocol)
@ -2433,7 +2450,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.pushEnabled(metricsOptionGroup.isMetricsPushEnabled)
.pushHost(
Strings.isNullOrEmpty(metricsOptionGroup.metricsPushHost)
? autoDiscoverDefaultIP().getHostAddress()
? p2PDiscoveryOptionGroup.autoDiscoverDefaultIP().getHostAddress()
: metricsOptionGroup.metricsPushHost)
.pushPort(metricsOptionGroup.metricsPushPort)
.pushInterval(metricsOptionGroup.metricsPushInterval)
@ -2796,10 +2813,12 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.p2pListenInterface(p2pListenInterface)
.p2pListenPort(p2pListenPort)
.maxPeers(maxPeers)
.limitRemoteWireConnectionsEnabled(isLimitRemoteWireConnectionsEnabled)
.limitRemoteWireConnectionsEnabled(
p2PDiscoveryOptionGroup.isLimitRemoteWireConnectionsEnabled)
.fractionRemoteConnectionsAllowed(
Fraction.fromPercentage(maxRemoteConnectionsPercentage).getValue())
.randomPeerPriority(randomPeerPriority)
Fraction.fromPercentage(p2PDiscoveryOptionGroup.maxRemoteConnectionsPercentage)
.getValue())
.randomPeerPriority(p2PDiscoveryOptionGroup.randomPeerPriority)
.networkingConfiguration(unstableNetworkingOptions.toDomainObject())
.graphQLConfiguration(graphQLConfiguration)
.jsonRpcConfiguration(jsonRpcConfiguration)
@ -2810,7 +2829,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.apiConfiguration(apiConfiguration)
.pidPath(pidPath)
.dataDir(dataDir())
.bannedNodeIds(bannedNodeIds)
.bannedNodeIds(p2PDiscoveryOptionGroup.bannedNodeIds)
.metricsSystem(metricsSystem)
.permissioningService(permissioningService)
.metricsConfiguration(metricsConfiguration)
@ -2859,16 +2878,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
"BesuCommand-Shutdown-Hook"));
}
// Used to discover the default IP of the client.
// Loopback IP is used by default as this is how smokeTests require it to be
// and it's probably a good security behaviour to default only on the localhost.
private InetAddress autoDiscoverDefaultIP() {
autoDiscoveredDefaultIP =
Optional.ofNullable(autoDiscoveredDefaultIP).orElseGet(InetAddress::getLoopbackAddress);
return autoDiscoveredDefaultIP;
}
private EthNetworkConfig updateNetworkConfig(final NetworkName network) {
final EthNetworkConfig.Builder builder =
new EthNetworkConfig.Builder(EthNetworkConfig.getNetworkConfig(network));
@ -2902,14 +2911,14 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
}
if (bootNodes == null) {
if (p2PDiscoveryOptionGroup.bootNodes == null) {
builder.setBootNodes(new ArrayList<>());
}
builder.setDnsDiscoveryUrl(null);
}
if (discoveryDnsUrl != null) {
builder.setDnsDiscoveryUrl(discoveryDnsUrl);
if (p2PDiscoveryOptionGroup.discoveryDnsUrl != null) {
builder.setDnsDiscoveryUrl(p2PDiscoveryOptionGroup.discoveryDnsUrl);
} else if (genesisConfigOptions != null) {
final Optional<String> discoveryDnsUrlFromGenesis =
genesisConfigOptions.getDiscoveryOptions().getDiscoveryDnsUrl();
@ -2921,9 +2930,9 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
List<EnodeURL> listBootNodes = null;
if (bootNodes != null) {
if (p2PDiscoveryOptionGroup.bootNodes != null) {
try {
listBootNodes = buildEnodes(bootNodes, getEnodeDnsConfiguration());
listBootNodes = buildEnodes(p2PDiscoveryOptionGroup.bootNodes, getEnodeDnsConfiguration());
} catch (final IllegalArgumentException e) {
throw new ParameterException(commandLine, e.getMessage());
}
@ -2935,7 +2944,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
}
if (listBootNodes != null) {
if (!peerDiscoveryEnabled) {
if (!p2PDiscoveryOptionGroup.peerDiscoveryEnabled) {
logger.warn("Discovery disabled: bootnodes will be ignored.");
}
DiscoveryConfiguration.assertValidBootnodes(listBootNodes);
@ -3069,7 +3078,8 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
*/
private List<Integer> getEffectivePorts() {
final List<Integer> effectivePorts = new ArrayList<>();
addPortIfEnabled(effectivePorts, p2pPort, p2pEnabled);
addPortIfEnabled(
effectivePorts, p2PDiscoveryOptionGroup.p2pPort, p2PDiscoveryOptionGroup.p2pEnabled);
addPortIfEnabled(
effectivePorts,
graphQlOptionGroup.graphQLHttpPort,

Loading…
Cancel
Save