@ -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 . p2 pEnabled ,
p2pTLSConfiguration ,
peerDiscoveryEnabled ,
p2PDiscoveryOptionGroup . p eerDiscoveryEnabled ,
ethNetworkConfig ,
maxPeers ,
p2pHost ,
p2pInterface ,
p2pPort ,
p2PDiscoveryOptionGroup . maxPeers ,
p2PDiscoveryOptionGroup . p2 pHost ,
p2PDiscoveryOptionGroup . p2 pInterface ,
p2PDiscoveryOptionGroup . p2 pPort ,
graphQLConfiguration ,
jsonRpcConfiguration ,
engineJsonRpcConfiguration ,
@ -1687,7 +1704,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
private void validateOptions ( ) {
issueOptionWarnings ( ) ;
validateP2PInterface ( p2pInterface ) ;
validateP2PInterface ( p2PDiscoveryOptionGroup . p2 pInterface ) ;
validateMiningParams ( ) ;
validateNatParams ( ) ;
validateNetStatsParams ( ) ;
@ -1819,7 +1836,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
logger ,
commandLine ,
"--p2p-enabled" ,
! p2pEnabled ,
! p2PDiscoveryOptionGroup . p2 pEnabled ,
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 . p eerDiscoveryEnabled ) {
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 ,