From f4dc48d94d276f1ed504b707b8f9ccf278a5cc63 Mon Sep 17 00:00:00 2001 From: Justin Florentine Date: Wed, 2 Oct 2024 11:46:34 -0400 Subject: [PATCH 1/8] Simplifying BesuCommand step 1 (#7682) Simplifying BesuCommand --------- Signed-off-by: Justin Florentine --- .../dsl/node/ProcessBesuNodeRunner.java | 2 +- .../org/hyperledger/besu/cli/BesuCommand.java | 305 ++++-------------- .../{stable => }/DataStorageOptions.java | 3 +- .../stable/ApiConfigurationOptions.java | 1 + .../stable/EngineRPCConfiguration.java | 36 +++ .../cli/options/stable/EngineRPCOptions.java | 81 +++++ .../cli/options/stable/GraphQlOptions.java | 1 + .../options/stable/JsonRpcHttpOptions.java | 34 +- .../options/stable/MetricsOptionGroup.java | 1 + .../options/stable/P2PDiscoveryOptions.java | 238 ++++++++++++++ .../options/stable/PermissionsOptions.java | 1 + .../options/unstable/MetricsCLIOptions.java | 1 + .../P2PTLSConfigOptions.java | 2 +- .../subcommands/storage/TrieLogHelper.java | 4 +- .../besu/components/BesuCommandModule.java | 16 +- .../besu/cli/CommandTestAbstract.java | 2 +- .../stable/DataStorageOptionsTest.java | 1 + .../besu/config/MergeConfigOptions.java | 2 + .../discovery/P2PDiscoveryConfiguration.java | 39 +++ 19 files changed, 501 insertions(+), 269 deletions(-) rename besu/src/main/java/org/hyperledger/besu/cli/options/{stable => }/DataStorageOptions.java (99%) create mode 100644 besu/src/main/java/org/hyperledger/besu/cli/options/stable/EngineRPCConfiguration.java create mode 100644 besu/src/main/java/org/hyperledger/besu/cli/options/stable/EngineRPCOptions.java create mode 100644 besu/src/main/java/org/hyperledger/besu/cli/options/stable/P2PDiscoveryOptions.java rename besu/src/main/java/org/hyperledger/besu/cli/options/{stable => unstable}/P2PTLSConfigOptions.java (99%) create mode 100644 ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/P2PDiscoveryConfiguration.java diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ProcessBesuNodeRunner.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ProcessBesuNodeRunner.java index 62951a442db..e08fb29f673 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ProcessBesuNodeRunner.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ProcessBesuNodeRunner.java @@ -17,8 +17,8 @@ import static com.google.common.base.Preconditions.checkState; import static java.nio.charset.StandardCharsets.UTF_8; +import org.hyperledger.besu.cli.options.DataStorageOptions; import org.hyperledger.besu.cli.options.TransactionPoolOptions; -import org.hyperledger.besu.cli.options.stable.DataStorageOptions; import org.hyperledger.besu.cli.options.unstable.NetworkingOptions; import org.hyperledger.besu.ethereum.api.jsonrpc.ipc.JsonRpcIpcConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index e93518cad43..fa59f48dd7b 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -24,7 +24,6 @@ import static org.hyperledger.besu.cli.util.CommandLineUtils.DEPENDENCY_WARNING_MSG; import static org.hyperledger.besu.cli.util.CommandLineUtils.isOptionSet; import static org.hyperledger.besu.controller.BesuController.DATABASE_PATH; -import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration.DEFAULT_ENGINE_JSON_RPC_PORT; import static org.hyperledger.besu.ethereum.api.jsonrpc.authentication.EngineAuthService.EPHEMERAL_JWT_FILE; import static org.hyperledger.besu.nat.kubernetes.KubernetesNatManager.DEFAULT_BESU_SERVICE_NAME_FILTER; @@ -38,22 +37,22 @@ import org.hyperledger.besu.cli.config.NetworkName; import org.hyperledger.besu.cli.config.ProfilesCompletionCandidates; import org.hyperledger.besu.cli.converter.MetricCategoryConverter; -import org.hyperledger.besu.cli.converter.PercentageConverter; -import org.hyperledger.besu.cli.converter.SubnetInfoConverter; import org.hyperledger.besu.cli.custom.JsonRPCAllowlistHostsProperty; import org.hyperledger.besu.cli.error.BesuExecutionExceptionHandler; import org.hyperledger.besu.cli.error.BesuParameterExceptionHandler; +import org.hyperledger.besu.cli.options.DataStorageOptions; import org.hyperledger.besu.cli.options.MiningOptions; import org.hyperledger.besu.cli.options.TransactionPoolOptions; import org.hyperledger.besu.cli.options.stable.ApiConfigurationOptions; -import org.hyperledger.besu.cli.options.stable.DataStorageOptions; +import org.hyperledger.besu.cli.options.stable.EngineRPCConfiguration; +import org.hyperledger.besu.cli.options.stable.EngineRPCOptions; import org.hyperledger.besu.cli.options.stable.EthstatsOptions; import org.hyperledger.besu.cli.options.stable.GraphQlOptions; import org.hyperledger.besu.cli.options.stable.JsonRpcHttpOptions; import org.hyperledger.besu.cli.options.stable.LoggingLevelOption; import org.hyperledger.besu.cli.options.stable.MetricsOptionGroup; import org.hyperledger.besu.cli.options.stable.NodePrivateKeyFileOption; -import org.hyperledger.besu.cli.options.stable.P2PTLSConfigOptions; +import org.hyperledger.besu.cli.options.stable.P2PDiscoveryOptions; import org.hyperledger.besu.cli.options.stable.PermissionsOptions; import org.hyperledger.besu.cli.options.stable.PluginsConfigurationOptions; import org.hyperledger.besu.cli.options.stable.RpcWebsocketOptions; @@ -67,6 +66,7 @@ import org.hyperledger.besu.cli.options.unstable.NatOptions; import org.hyperledger.besu.cli.options.unstable.NativeLibraryOptions; import org.hyperledger.besu.cli.options.unstable.NetworkingOptions; +import org.hyperledger.besu.cli.options.unstable.P2PTLSConfigOptions; import org.hyperledger.besu.cli.options.unstable.PrivacyPluginOptions; import org.hyperledger.besu.cli.options.unstable.RPCOptions; import org.hyperledger.besu.cli.options.unstable.SynchronizerOptions; @@ -124,6 +124,7 @@ import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; import org.hyperledger.besu.ethereum.mainnet.FrontierTargetingGasLimitCalculator; import org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration; +import org.hyperledger.besu.ethereum.p2p.discovery.P2PDiscoveryConfiguration; import org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration; import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl; import org.hyperledger.besu.ethereum.p2p.peers.StaticNodesParser; @@ -209,7 +210,6 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.math.BigInteger; -import java.net.InetAddress; import java.net.SocketException; import java.net.URI; import java.net.URL; @@ -247,7 +247,6 @@ import io.vertx.core.VertxOptions; import io.vertx.core.json.DecodeException; import io.vertx.core.metrics.MetricsOptions; -import org.apache.commons.net.util.SubnetUtils.SubnetInfo; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; import org.slf4j.Logger; @@ -416,7 +415,9 @@ void setUserName(final String userName) { // P2P Discovery Option Group @CommandLine.ArgGroup(validate = false, heading = "@|bold P2P Discovery Options|@%n") - P2PDiscoveryOptionGroup p2PDiscoveryOptionGroup = new P2PDiscoveryOptionGroup(); + P2PDiscoveryOptions p2PDiscoveryOptions = new P2PDiscoveryOptions(); + + P2PDiscoveryConfiguration p2PDiscoveryConfig; private final TransactionSelectionServiceImpl transactionSelectionServiceImpl; private final TransactionPoolValidatorServiceImpl transactionValidatorServiceImpl; @@ -424,163 +425,6 @@ void setUserName(final String userName) { private final BlockchainServiceImpl blockchainServiceImpl; private BesuComponent besuComponent; - static class P2PDiscoveryOptionGroup { - - // Public IP stored to prevent having to research it each time we need it. - private InetAddress autoDiscoveredDefaultIP = null; - - // 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; - - // 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 = "", - description = - "Comma separated enode URLs for P2P discovery bootstrap. " - + "Default is a predefined list.", - split = ",", - arity = "0..*") - private final List bootNodes = 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 = {"--max-peers", "--p2p-peer-upper-bound"}, - 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 Percentage maxRemoteConnectionsPercentage = - Fraction.fromFloat(DEFAULT_FRACTION_REMOTE_WIRE_CONNECTIONS_ALLOWED).toPercentage(); - - @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 = Boolean.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 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()); - } - } - - // Boolean option to set that in a PoA network the bootnodes should always be queried during - // peer table refresh. If this flag is disabled bootnodes are only sent FINDN requests on first - // startup, meaning that an offline bootnode or network outage at the client can prevent it - // discovering any peers without a restart. - @Option( - names = {"--poa-discovery-retry-bootnodes"}, - description = - "Always use of bootnodes for discovery in PoA networks. Disabling this reverts " - + " to the same behaviour as non-PoA networks, where neighbours are only discovered from bootnodes on first startup." - + "(default: ${DEFAULT-VALUE})", - arity = "1") - private final Boolean poaDiscoveryRetryBootnodes = true; - - private Collection 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 = {"--net-restrict"}, - arity = "1..*", - split = ",", - converter = SubnetInfoConverter.class, - description = - "Comma-separated list of allowed IP subnets (e.g., '192.168.1.0/24,10.0.0.0/8').") - private List allowedSubnets; - } - @Option( names = {"--sync-mode"}, paramLabel = MANDATORY_MODE_FORMAT_HELP, @@ -647,42 +491,9 @@ private InetAddress autoDiscoverDefaultIP() { // Engine JSON-PRC Options @CommandLine.ArgGroup(validate = false, heading = "@|bold Engine JSON-RPC Options|@%n") - EngineRPCOptionGroup engineRPCOptionGroup = new EngineRPCOptionGroup(); - - static class EngineRPCOptionGroup { - @Option( - names = {"--engine-rpc-enabled"}, - description = - "enable the engine api, even in the absence of merge-specific configurations.") - private final Boolean overrideEngineRpcEnabled = false; - - @Option( - names = {"--engine-rpc-port", "--engine-rpc-http-port"}, - paramLabel = MANDATORY_PORT_FORMAT_HELP, - description = "Port to provide consensus client APIS on (default: ${DEFAULT-VALUE})", - arity = "1") - private final Integer engineRpcPort = DEFAULT_ENGINE_JSON_RPC_PORT; + EngineRPCOptions engineRPCOptions = new EngineRPCOptions(); - @Option( - names = {"--engine-jwt-secret"}, - paramLabel = MANDATORY_FILE_FORMAT_HELP, - description = "Path to file containing shared secret key for JWT signature verification") - private final Path engineJwtKeyFile = null; - - @Option( - names = {"--engine-jwt-disabled"}, - description = "Disable authentication for Engine APIs (default: ${DEFAULT-VALUE})") - private final Boolean isEngineAuthDisabled = false; - - @Option( - names = {"--engine-host-allowlist"}, - paramLabel = "[,...]... or * or all", - description = - "Comma separated list of hostnames to allow for ENGINE API access (applies to both HTTP and websockets), or * to accept any host (default: ${DEFAULT-VALUE})", - defaultValue = "localhost,127.0.0.1") - private final JsonRPCAllowlistHostsProperty engineHostsAllowlist = - new JsonRPCAllowlistHostsProperty(); - } + EngineRPCConfiguration engineRPCConfig = engineRPCOptions.toDomainObject(); // JSON-RPC HTTP Options @CommandLine.ArgGroup(validate = false, heading = "@|bold JSON-RPC HTTP Options|@%n") @@ -1409,13 +1220,13 @@ private void preSynchronization() { private Runner buildRunner() { return synchronize( besuController, - p2PDiscoveryOptionGroup.p2pEnabled, + p2PDiscoveryConfig.p2pEnabled(), p2pTLSConfiguration, - p2PDiscoveryOptionGroup.peerDiscoveryEnabled, + p2PDiscoveryConfig.peerDiscoveryEnabled(), ethNetworkConfig, - p2PDiscoveryOptionGroup.p2pHost, - p2PDiscoveryOptionGroup.p2pInterface, - p2PDiscoveryOptionGroup.p2pPort, + p2PDiscoveryConfig.p2pHost(), + p2PDiscoveryConfig.p2pInterface(), + p2PDiscoveryConfig.p2pPort(), graphQLConfiguration, jsonRpcConfiguration, engineJsonRpcConfiguration, @@ -1614,7 +1425,7 @@ private void configureNativeLibs() { private void validateOptions() { validateRequiredOptions(); issueOptionWarnings(); - validateP2PInterface(p2PDiscoveryOptionGroup.p2pInterface); + validateP2PInterface(p2PDiscoveryOptions.p2pInterface); validateMiningParams(); validateNatParams(); validateNetStatsParams(); @@ -1750,13 +1561,12 @@ private void validateDnsOptionsParams() { } private void ensureValidPeerBoundParams() { - maxPeers = p2PDiscoveryOptionGroup.maxPeers; + maxPeers = p2PDiscoveryOptions.maxPeers; final Boolean isLimitRemoteWireConnectionsEnabled = - p2PDiscoveryOptionGroup.isLimitRemoteWireConnectionsEnabled; + p2PDiscoveryOptions.isLimitRemoteWireConnectionsEnabled; if (isLimitRemoteWireConnectionsEnabled) { final float fraction = - Fraction.fromPercentage(p2PDiscoveryOptionGroup.maxRemoteConnectionsPercentage) - .getValue(); + Fraction.fromPercentage(p2PDiscoveryOptions.maxRemoteConnectionsPercentage).getValue(); checkState( fraction >= 0.0 && fraction <= 1.0, "Fraction of remote connections allowed must be between 0.0 and 1.0 (inclusive)."); @@ -1820,7 +1630,7 @@ private void issueOptionWarnings() { logger, commandLine, "--p2p-enabled", - !p2PDiscoveryOptionGroup.p2pEnabled, + !p2PDiscoveryOptions.p2pEnabled, asList( "--bootnodes", "--discovery-enabled", @@ -1861,6 +1671,8 @@ && isOptionSet(commandLine, "--sync-min-peers")) { } private void configure() throws Exception { + p2PDiscoveryConfig = p2PDiscoveryOptions.toDomainObject(); + engineRPCConfig = engineRPCOptions.toDomainObject(); checkPortClash(); checkIfRequiredPortsAreAvailable(); syncMode = getDefaultSyncModeIfNotSet(); @@ -1870,25 +1682,18 @@ private void configure() throws Exception { jsonRpcConfiguration = jsonRpcHttpOptions.jsonRpcConfiguration( - hostsAllowlist, - p2PDiscoveryOptionGroup.autoDiscoverDefaultIP().getHostAddress(), - unstableRPCOptions.getHttpTimeoutSec()); + hostsAllowlist, p2PDiscoveryOptions.p2pHost, unstableRPCOptions.getHttpTimeoutSec()); if (isEngineApiEnabled()) { - engineJsonRpcConfiguration = - createEngineJsonRpcConfiguration( - engineRPCOptionGroup.engineRpcPort, engineRPCOptionGroup.engineHostsAllowlist); + engineJsonRpcConfiguration = createEngineJsonRpcConfiguration(); } p2pTLSConfiguration = p2pTLSConfigOptions.p2pTLSConfiguration(commandLine); graphQLConfiguration = graphQlOptions.graphQLConfiguration( - hostsAllowlist, - p2PDiscoveryOptionGroup.autoDiscoverDefaultIP().getHostAddress(), - unstableRPCOptions.getHttpTimeoutSec()); + hostsAllowlist, p2PDiscoveryOptions.p2pHost, unstableRPCOptions.getHttpTimeoutSec()); + webSocketConfiguration = rpcWebsocketOptions.webSocketConfiguration( - hostsAllowlist, - p2PDiscoveryOptionGroup.autoDiscoverDefaultIP().getHostAddress(), - unstableRPCOptions.getWsTimeoutSec()); + hostsAllowlist, p2PDiscoveryConfig.p2pHost(), unstableRPCOptions.getWsTimeoutSec()); jsonRpcIpcConfiguration = jsonRpcIpcConfiguration( unstableIpcOptions.isEnabled(), @@ -2008,32 +1813,31 @@ public BesuControllerBuilder setupControllerBuilder() { .requiredBlocks(requiredBlocks) .reorgLoggingThreshold(reorgLoggingThreshold) .evmConfiguration(unstableEvmOptions.toDomainObject()) - .maxPeers(p2PDiscoveryOptionGroup.maxPeers) + .maxPeers(p2PDiscoveryOptions.maxPeers) .maxRemotelyInitiatedPeers(maxRemoteInitiatedPeers) - .randomPeerPriority(p2PDiscoveryOptionGroup.randomPeerPriority) + .randomPeerPriority(p2PDiscoveryOptions.randomPeerPriority) .chainPruningConfiguration(unstableChainPruningOptions.toDomainObject()) .cacheLastBlocks(numberOfblocksToCache) .genesisStateHashCacheEnabled(genesisStateHashCacheEnabled) .besuComponent(besuComponent); } - private JsonRpcConfiguration createEngineJsonRpcConfiguration( - final Integer engineListenPort, final List allowCallsFrom) { + private JsonRpcConfiguration createEngineJsonRpcConfiguration() { jsonRpcHttpOptions.checkDependencies(logger, commandLine); final JsonRpcConfiguration engineConfig = jsonRpcHttpOptions.jsonRpcConfiguration( - allowCallsFrom, - p2PDiscoveryOptionGroup.autoDiscoverDefaultIP().getHostAddress(), + engineRPCConfig.engineHostsAllowlist(), + p2PDiscoveryConfig.p2pHost(), unstableRPCOptions.getWsTimeoutSec()); - engineConfig.setPort(engineListenPort); + engineConfig.setPort(engineRPCConfig.engineRpcPort()); engineConfig.setRpcApis(Arrays.asList("ENGINE", "ETH")); engineConfig.setEnabled(isEngineApiEnabled()); - if (!engineRPCOptionGroup.isEngineAuthDisabled) { + if (!engineRPCConfig.isEngineAuthDisabled()) { engineConfig.setAuthenticationEnabled(true); engineConfig.setAuthenticationAlgorithm(JwtAlgorithm.HS256); - if (Objects.nonNull(engineRPCOptionGroup.engineJwtKeyFile) - && java.nio.file.Files.exists(engineRPCOptionGroup.engineJwtKeyFile)) { - engineConfig.setAuthenticationPublicKeyFile(engineRPCOptionGroup.engineJwtKeyFile.toFile()); + if (Objects.nonNull(engineRPCConfig.engineJwtKeyFile()) + && java.nio.file.Files.exists(engineRPCConfig.engineJwtKeyFile())) { + engineConfig.setAuthenticationPublicKeyFile(engineRPCConfig.engineJwtKeyFile().toFile()); } else { logger.warn( "Engine API authentication enabled without key file. Expect ephemeral jwt.hex file in datadir"); @@ -2090,7 +1894,7 @@ public MetricsConfiguration metricsConfiguration() { .enabled(metricsOptionGroup.getMetricsEnabled()) .host( Strings.isNullOrEmpty(metricsOptionGroup.getMetricsHost()) - ? p2PDiscoveryOptionGroup.autoDiscoverDefaultIP().getHostAddress() + ? p2PDiscoveryOptions.p2pHost : metricsOptionGroup.getMetricsHost()) .port(metricsOptionGroup.getMetricsPort()) .protocol(metricsOptionGroup.getMetricsProtocol()) @@ -2098,7 +1902,7 @@ public MetricsConfiguration metricsConfiguration() { .pushEnabled(metricsOptionGroup.getMetricsPushEnabled()) .pushHost( Strings.isNullOrEmpty(metricsOptionGroup.getMetricsPushHost()) - ? p2PDiscoveryOptionGroup.autoDiscoverDefaultIP().getHostAddress() + ? p2PDiscoveryOptions.autoDiscoverDefaultIP().getHostAddress() : metricsOptionGroup.getMetricsPushHost()) .pushPort(metricsOptionGroup.getMetricsPushPort()) .pushInterval(metricsOptionGroup.getMetricsPushInterval()) @@ -2441,7 +2245,7 @@ private Runner synchronize( .apiConfiguration(apiConfiguration) .pidPath(pidPath) .dataDir(dataDir()) - .bannedNodeIds(p2PDiscoveryOptionGroup.bannedNodeIds) + .bannedNodeIds(p2PDiscoveryConfig.bannedNodeIds()) .metricsSystem((ObservableMetricsSystem) besuComponent.getMetricsSystem()) .permissioningService(permissioningService) .metricsConfiguration(metricsConfiguration) @@ -2453,8 +2257,8 @@ private Runner synchronize( .storageProvider(keyValueStorageProvider(keyValueStorageName)) .rpcEndpointService(rpcEndpointServiceImpl) .enodeDnsConfiguration(getEnodeDnsConfiguration()) - .allowedSubnets(p2PDiscoveryOptionGroup.allowedSubnets) - .poaDiscoveryRetryBootnodes(p2PDiscoveryOptionGroup.poaDiscoveryRetryBootnodes) + .allowedSubnets(p2PDiscoveryConfig.allowedSubnets()) + .poaDiscoveryRetryBootnodes(p2PDiscoveryConfig.poaDiscoveryRetryBootnodes()) .build(); addShutdownHook(runner); @@ -2529,7 +2333,7 @@ private EthNetworkConfig updateNetworkConfig(final NetworkName network) { } } - if (p2PDiscoveryOptionGroup.bootNodes == null) { + if (p2PDiscoveryOptions.bootNodes == null) { builder.setBootNodes(new ArrayList<>()); } builder.setDnsDiscoveryUrl(null); @@ -2541,8 +2345,8 @@ private EthNetworkConfig updateNetworkConfig(final NetworkName network) { builder.setNetworkId(networkId); } - if (p2PDiscoveryOptionGroup.discoveryDnsUrl != null) { - builder.setDnsDiscoveryUrl(p2PDiscoveryOptionGroup.discoveryDnsUrl); + if (p2PDiscoveryOptions.discoveryDnsUrl != null) { + builder.setDnsDiscoveryUrl(p2PDiscoveryOptions.discoveryDnsUrl); } else { final Optional discoveryDnsUrlFromGenesis = genesisConfigOptionsSupplier.get().getDiscoveryOptions().getDiscoveryDnsUrl(); @@ -2550,9 +2354,9 @@ private EthNetworkConfig updateNetworkConfig(final NetworkName network) { } List listBootNodes = null; - if (p2PDiscoveryOptionGroup.bootNodes != null) { + if (p2PDiscoveryOptions.bootNodes != null) { try { - listBootNodes = buildEnodes(p2PDiscoveryOptionGroup.bootNodes, getEnodeDnsConfiguration()); + listBootNodes = buildEnodes(p2PDiscoveryOptions.bootNodes, getEnodeDnsConfiguration()); } catch (final IllegalArgumentException e) { throw new ParameterException(commandLine, e.getMessage()); } @@ -2564,7 +2368,7 @@ private EthNetworkConfig updateNetworkConfig(final NetworkName network) { } } if (listBootNodes != null) { - if (!p2PDiscoveryOptionGroup.peerDiscoveryEnabled) { + if (!p2PDiscoveryOptions.peerDiscoveryEnabled) { logger.warn("Discovery disabled: bootnodes will be ignored."); } DiscoveryConfiguration.assertValidBootnodes(listBootNodes); @@ -2699,12 +2503,12 @@ protected void checkIfRequiredPortsAreAvailable() { .filter(port -> port > 0) .forEach( port -> { - if (port.equals(p2PDiscoveryOptionGroup.p2pPort) + if (port.equals(p2PDiscoveryConfig.p2pPort()) && (NetworkUtility.isPortUnavailableForTcp(port) || NetworkUtility.isPortUnavailableForUdp(port))) { unavailablePorts.add(port); } - if (!port.equals(p2PDiscoveryOptionGroup.p2pPort) + if (!port.equals(p2PDiscoveryConfig.p2pPort()) && NetworkUtility.isPortUnavailableForTcp(port)) { unavailablePorts.add(port); } @@ -2724,15 +2528,14 @@ protected void checkIfRequiredPortsAreAvailable() { */ private List getEffectivePorts() { final List effectivePorts = new ArrayList<>(); - addPortIfEnabled( - effectivePorts, p2PDiscoveryOptionGroup.p2pPort, p2PDiscoveryOptionGroup.p2pEnabled); + addPortIfEnabled(effectivePorts, p2PDiscoveryOptions.p2pPort, p2PDiscoveryOptions.p2pEnabled); addPortIfEnabled( effectivePorts, graphQlOptions.getGraphQLHttpPort(), graphQlOptions.isGraphQLHttpEnabled()); addPortIfEnabled( effectivePorts, jsonRpcHttpOptions.getRpcHttpPort(), jsonRpcHttpOptions.isRpcHttpEnabled()); addPortIfEnabled( effectivePorts, rpcWebsocketOptions.getRpcWsPort(), rpcWebsocketOptions.isRpcWsEnabled()); - addPortIfEnabled(effectivePorts, engineRPCOptionGroup.engineRpcPort, isEngineApiEnabled()); + addPortIfEnabled(effectivePorts, engineRPCConfig.engineRpcPort(), isEngineApiEnabled()); addPortIfEnabled( effectivePorts, metricsOptionGroup.getMetricsPort(), @@ -2859,7 +2662,7 @@ private boolean isMergeEnabled() { } private boolean isEngineApiEnabled() { - return engineRPCOptionGroup.overrideEngineRpcEnabled || isMergeEnabled(); + return engineRPCConfig.overrideEngineRpcEnabled() || isMergeEnabled(); } private SyncMode getDefaultSyncModeIfNotSet() { diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/DataStorageOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/DataStorageOptions.java similarity index 99% rename from besu/src/main/java/org/hyperledger/besu/cli/options/stable/DataStorageOptions.java rename to besu/src/main/java/org/hyperledger/besu/cli/options/DataStorageOptions.java index 3d53a595ec8..b442f6ee034 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/DataStorageOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/DataStorageOptions.java @@ -12,7 +12,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.hyperledger.besu.cli.options.stable; +package org.hyperledger.besu.cli.options; import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.DEFAULT_BONSAI_LIMIT_TRIE_LOGS_ENABLED; import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.DEFAULT_BONSAI_MAX_LAYERS_TO_LOAD; @@ -22,7 +22,6 @@ import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.Unstable.DEFAULT_BONSAI_CODE_USING_CODE_HASH_ENABLED; import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.Unstable.DEFAULT_BONSAI_FULL_FLAT_DB_ENABLED; -import org.hyperledger.besu.cli.options.CLIOptions; import org.hyperledger.besu.cli.util.CommandLineUtils; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration; diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/ApiConfigurationOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/ApiConfigurationOptions.java index fbed68de0cd..d6bc17026cd 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/ApiConfigurationOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/ApiConfigurationOptions.java @@ -28,6 +28,7 @@ * Handles configuration options for the API in Besu, including gas price settings, RPC log range, * and trace filter range. */ +// TODO: implement CLIOption public class ApiConfigurationOptions { /** Default constructor. */ public ApiConfigurationOptions() {} diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/EngineRPCConfiguration.java b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/EngineRPCConfiguration.java new file mode 100644 index 00000000000..c0eb9d1be08 --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/EngineRPCConfiguration.java @@ -0,0 +1,36 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.cli.options.stable; + +import org.hyperledger.besu.cli.custom.JsonRPCAllowlistHostsProperty; + +import java.nio.file.Path; + +/** + * Command line options for configuring Engine RPC on the node. + * + * @param overrideEngineRpcEnabled enable the engine api, even in the absence of merge-specific + * configurations. + * @param engineRpcPort Port to provide consensus client APIS on + * @param engineJwtKeyFile Path to file containing shared secret key for JWT signature verification + * @param isEngineAuthDisabled Disable authentication for Engine APIs + * @param engineHostsAllowlist List of hosts to allowlist for Engine APIs + */ +public record EngineRPCConfiguration( + Boolean overrideEngineRpcEnabled, + Integer engineRpcPort, + Path engineJwtKeyFile, + Boolean isEngineAuthDisabled, + JsonRPCAllowlistHostsProperty engineHostsAllowlist) {} diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/EngineRPCOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/EngineRPCOptions.java new file mode 100644 index 00000000000..1aa5b3d3263 --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/EngineRPCOptions.java @@ -0,0 +1,81 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.cli.options.stable; + +import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration.DEFAULT_ENGINE_JSON_RPC_PORT; + +import org.hyperledger.besu.cli.DefaultCommandValues; +import org.hyperledger.besu.cli.custom.JsonRPCAllowlistHostsProperty; +import org.hyperledger.besu.cli.options.CLIOptions; +import org.hyperledger.besu.cli.util.CommandLineUtils; + +import java.nio.file.Path; +import java.util.List; + +import picocli.CommandLine; + +/** Command line options for configuring Engine RPC on the node. */ +public class EngineRPCOptions implements CLIOptions { + + /** Default constructor */ + public EngineRPCOptions() {} + + @CommandLine.Option( + names = {"--engine-rpc-enabled"}, + description = "enable the engine api, even in the absence of merge-specific configurations.") + private final Boolean overrideEngineRpcEnabled = false; + + @CommandLine.Option( + names = {"--engine-rpc-port", "--engine-rpc-http-port"}, + paramLabel = DefaultCommandValues.MANDATORY_PORT_FORMAT_HELP, + description = "Port to provide consensus client APIS on (default: ${DEFAULT-VALUE})", + arity = "1") + private final Integer engineRpcPort = DEFAULT_ENGINE_JSON_RPC_PORT; + + @CommandLine.Option( + names = {"--engine-jwt-secret"}, + paramLabel = DefaultCommandValues.MANDATORY_FILE_FORMAT_HELP, + description = "Path to file containing shared secret key for JWT signature verification") + private final Path engineJwtKeyFile = null; + + @CommandLine.Option( + names = {"--engine-jwt-disabled"}, + description = "Disable authentication for Engine APIs (default: ${DEFAULT-VALUE})") + private final Boolean isEngineAuthDisabled = false; + + @CommandLine.Option( + names = {"--engine-host-allowlist"}, + paramLabel = "[,...]... or * or all", + description = + "Comma separated list of hostnames to allow for ENGINE API access (applies to both HTTP and websockets), or * to accept any host (default: ${DEFAULT-VALUE})", + defaultValue = "localhost,127.0.0.1") + private final JsonRPCAllowlistHostsProperty engineHostsAllowlist = + new JsonRPCAllowlistHostsProperty(); + + @Override + public EngineRPCConfiguration toDomainObject() { + return new EngineRPCConfiguration( + overrideEngineRpcEnabled, + engineRpcPort, + engineJwtKeyFile, + isEngineAuthDisabled, + engineHostsAllowlist); + } + + @Override + public List getCLIOptions() { + return CommandLineUtils.getCLIOptions(this, new EngineRPCOptions()); + } +} diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/GraphQlOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/GraphQlOptions.java index 77cc1703052..6aac24a6fbc 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/GraphQlOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/GraphQlOptions.java @@ -29,6 +29,7 @@ import picocli.CommandLine; /** Handles configuration options for the GraphQL HTTP service in Besu. */ +// TODO: implement CLIOptions public class GraphQlOptions { @CommandLine.Option( names = {"--graphql-http-enabled"}, diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/JsonRpcHttpOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/JsonRpcHttpOptions.java index 026b83b5537..1c7e0f543e9 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/JsonRpcHttpOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/JsonRpcHttpOptions.java @@ -52,6 +52,7 @@ * Handles configuration options for the JSON-RPC HTTP service, including validation and creation of * a JSON-RPC configuration. */ +// TODO: implement CLIOption public class JsonRpcHttpOptions { @CommandLine.Option( names = {"--rpc-http-enabled"}, @@ -265,37 +266,50 @@ && rpcHttpAuthenticationCredentialsFile(commandLine) == null /** * Creates a JsonRpcConfiguration based on the provided options. * - * @param hostsAllowlist List of hosts allowed - * @param defaultHostAddress Default host address - * @param timoutSec timeout in seconds - * @return A JsonRpcConfiguration instance + * @return configuration populated from options or defaults */ - public JsonRpcConfiguration jsonRpcConfiguration( - final List hostsAllowlist, final String defaultHostAddress, final Long timoutSec) { + public JsonRpcConfiguration jsonRpcConfiguration() { final JsonRpcConfiguration jsonRpcConfiguration = JsonRpcConfiguration.createDefault(); jsonRpcConfiguration.setEnabled(isRpcHttpEnabled); - jsonRpcConfiguration.setHost( - Strings.isNullOrEmpty(rpcHttpHost) ? defaultHostAddress : rpcHttpHost); jsonRpcConfiguration.setPort(rpcHttpPort); jsonRpcConfiguration.setMaxActiveConnections(rpcHttpMaxConnections); jsonRpcConfiguration.setCorsAllowedDomains(rpcHttpCorsAllowedOrigins); jsonRpcConfiguration.setRpcApis(rpcHttpApis.stream().distinct().collect(Collectors.toList())); jsonRpcConfiguration.setNoAuthRpcApis( rpcHttpApiMethodsNoAuth.stream().distinct().collect(Collectors.toList())); - jsonRpcConfiguration.setHostsAllowlist(hostsAllowlist); jsonRpcConfiguration.setAuthenticationEnabled(isRpcHttpAuthenticationEnabled); jsonRpcConfiguration.setAuthenticationCredentialsFile(rpcHttpAuthenticationCredentialsFile); jsonRpcConfiguration.setAuthenticationPublicKeyFile(rpcHttpAuthenticationPublicKeyFile); jsonRpcConfiguration.setAuthenticationAlgorithm(rpcHttpAuthenticationAlgorithm); jsonRpcConfiguration.setTlsConfiguration(rpcHttpTlsConfiguration()); - jsonRpcConfiguration.setHttpTimeoutSec(timoutSec); jsonRpcConfiguration.setMaxBatchSize(rpcHttpMaxBatchSize); jsonRpcConfiguration.setMaxRequestContentLength(rpcHttpMaxRequestContentLength); jsonRpcConfiguration.setPrettyJsonEnabled(prettyJsonEnabled); return jsonRpcConfiguration; } + /** + * Creates a JsonRpcConfiguration based on the provided options. + * + * @param hostsAllowlist List of hosts allowed + * @param defaultHostAddress Default host address + * @param timoutSec timeout in seconds + * @return A JsonRpcConfiguration instance + */ + public JsonRpcConfiguration jsonRpcConfiguration( + final List hostsAllowlist, final String defaultHostAddress, final Long timoutSec) { + + final JsonRpcConfiguration jsonRpcConfiguration = this.jsonRpcConfiguration(); + + jsonRpcConfiguration.setHost( + Strings.isNullOrEmpty(rpcHttpHost) ? defaultHostAddress : rpcHttpHost); + jsonRpcConfiguration.setHostsAllowlist(hostsAllowlist); + ; + jsonRpcConfiguration.setHttpTimeoutSec(timoutSec); + return jsonRpcConfiguration; + } + /** * Checks dependencies between options. * diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/MetricsOptionGroup.java b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/MetricsOptionGroup.java index add2bf16553..1c17e1cf9dd 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/MetricsOptionGroup.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/MetricsOptionGroup.java @@ -30,6 +30,7 @@ import picocli.CommandLine; /** Command line options for configuring metrics. */ +// TODO: implement CLIOption and rename to drop the Group public class MetricsOptionGroup { @CommandLine.Option( names = {"--metrics-enabled"}, diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/P2PDiscoveryOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/P2PDiscoveryOptions.java new file mode 100644 index 00000000000..21c24b3e278 --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/P2PDiscoveryOptions.java @@ -0,0 +1,238 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.cli.options.stable; + +import org.hyperledger.besu.cli.DefaultCommandValues; +import org.hyperledger.besu.cli.converter.PercentageConverter; +import org.hyperledger.besu.cli.converter.SubnetInfoConverter; +import org.hyperledger.besu.cli.options.CLIOptions; +import org.hyperledger.besu.cli.util.CommandLineUtils; +import org.hyperledger.besu.ethereum.p2p.discovery.P2PDiscoveryConfiguration; +import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl; +import org.hyperledger.besu.util.NetworkUtility; +import org.hyperledger.besu.util.number.Fraction; +import org.hyperledger.besu.util.number.Percentage; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.apache.commons.net.util.SubnetUtils; +import org.apache.tuweni.bytes.Bytes; +import picocli.CommandLine; + +/** Command line options for configuring P2P discovery on the node. */ +public class P2PDiscoveryOptions implements CLIOptions { + + /** Default constructor */ + public P2PDiscoveryOptions() {} + + // Public IP stored to prevent having to research it each time we need it. + private InetAddress autoDiscoveredDefaultIP = null; + + /** Completely disables P2P within Besu. */ + @CommandLine.Option( + names = {"--p2p-enabled"}, + description = "Enable P2P functionality (default: ${DEFAULT-VALUE})", + arity = "1") + public 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. + @CommandLine.Option( + names = {"--discovery-enabled"}, + description = "Enable P2P discovery (default: ${DEFAULT-VALUE})", + arity = "1") + public final Boolean peerDiscoveryEnabled = 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. + @CommandLine.Option( + names = {"--bootnodes"}, + paramLabel = "", + description = + "Comma separated enode URLs for P2P discovery bootstrap. " + + "Default is a predefined list.", + split = ",", + arity = "0..*") + public final List bootNodes = null; + + /** The IP the node advertises to peers for P2P communication. */ + @SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings. + @CommandLine.Option( + names = {"--p2p-host"}, + paramLabel = DefaultCommandValues.MANDATORY_HOST_FORMAT_HELP, + description = "IP address this node advertises to its peers (default: ${DEFAULT-VALUE})", + arity = "1") + public String p2pHost = autoDiscoverDefaultIP().getHostAddress(); + + /** The network interface address on which this node listens for P2P communication. */ + @SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings. + @CommandLine.Option( + names = {"--p2p-interface"}, + paramLabel = DefaultCommandValues.MANDATORY_HOST_FORMAT_HELP, + description = + "The network interface address on which this node listens for P2P communication (default: ${DEFAULT-VALUE})", + arity = "1") + public String p2pInterface = NetworkUtility.INADDR_ANY; + + /** The port on which this node listens for P2P communication. */ + @CommandLine.Option( + names = {"--p2p-port"}, + paramLabel = DefaultCommandValues.MANDATORY_PORT_FORMAT_HELP, + description = "Port on which to listen for P2P communication (default: ${DEFAULT-VALUE})", + arity = "1") + public final Integer p2pPort = EnodeURLImpl.DEFAULT_LISTENING_PORT; + + /** The maximum number of peers this node can connect to. */ + @CommandLine.Option( + names = {"--max-peers", "--p2p-peer-upper-bound"}, + paramLabel = DefaultCommandValues.MANDATORY_INTEGER_FORMAT_HELP, + description = "Maximum P2P connections that can be established (default: ${DEFAULT-VALUE})") + public final Integer maxPeers = DefaultCommandValues.DEFAULT_MAX_PEERS; + + /** Boolean option to limit the number of P2P connections initiated remotely. */ + @CommandLine.Option( + names = {"--remote-connections-limit-enabled"}, + description = + "Whether to limit the number of P2P connections initiated remotely. (default: ${DEFAULT-VALUE})") + public final Boolean isLimitRemoteWireConnectionsEnabled = true; + + /** The maximum percentage of P2P connections that can be initiated remotely. */ + @CommandLine.Option( + names = {"--remote-connections-max-percentage"}, + paramLabel = DefaultCommandValues.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) + public final Percentage maxRemoteConnectionsPercentage = + Fraction.fromFloat(DefaultCommandValues.DEFAULT_FRACTION_REMOTE_WIRE_CONNECTIONS_ALLOWED) + .toPercentage(); + + /** The URL to use for DNS discovery. */ + @SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings. + @CommandLine.Option( + names = {"--discovery-dns-url"}, + description = "Specifies the URL to use for DNS discovery") + public String discoveryDnsUrl = null; + + /** Boolean option to allow for incoming connections to be prioritized randomly. */ + @CommandLine.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})") + public final Boolean randomPeerPriority = Boolean.FALSE; + + /** A list of node IDs to ban from the P2P network. */ + @CommandLine.Option( + names = {"--banned-node-ids", "--banned-node-id"}, + paramLabel = DefaultCommandValues.MANDATORY_NODE_ID_FORMAT_HELP, + description = "A list of node IDs to ban from the P2P network.", + split = ",", + arity = "1..*") + void setBannedNodeIds(final List values) { + try { + bannedNodeIds = + values.stream() + .filter(value -> !value.isEmpty()) + .map(EnodeURLImpl::parseNodeId) + .collect(Collectors.toList()); + } catch (final IllegalArgumentException e) { + throw new CommandLine.ParameterException( + new CommandLine(this), "Invalid ids supplied to '--banned-node-ids'. " + e.getMessage()); + } + } + + // Boolean option to set that in a PoA network the bootnodes should always be queried during + // peer table refresh. If this flag is disabled bootnodes are only sent FINDN requests on first + // startup, meaning that an offline bootnode or network outage at the client can prevent it + // discovering any peers without a restart. + @CommandLine.Option( + names = {"--poa-discovery-retry-bootnodes"}, + description = + "Always use of bootnodes for discovery in PoA networks. Disabling this reverts " + + " to the same behaviour as non-PoA networks, where neighbours are only discovered from bootnodes on first startup." + + "(default: ${DEFAULT-VALUE})", + arity = "1") + private final Boolean poaDiscoveryRetryBootnodes = true; + + private Collection bannedNodeIds = new ArrayList<>(); + + /** + * Auto-discovers the default IP of the client. + * + * @return machine loopback address + */ + // 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. + public InetAddress autoDiscoverDefaultIP() { + autoDiscoveredDefaultIP = + Optional.ofNullable(autoDiscoveredDefaultIP).orElseGet(InetAddress::getLoopbackAddress); + + return autoDiscoveredDefaultIP; + } + + @CommandLine.Option( + names = {"--net-restrict"}, + arity = "1..*", + split = ",", + converter = SubnetInfoConverter.class, + description = + "Comma-separated list of allowed IP subnets (e.g., '192.168.1.0/24,10.0.0.0/8').") + private List allowedSubnets; + + @Override + public P2PDiscoveryConfiguration toDomainObject() { + return new P2PDiscoveryConfiguration( + p2pEnabled, + peerDiscoveryEnabled, + p2pHost, + p2pInterface, + p2pPort, + maxPeers, + isLimitRemoteWireConnectionsEnabled, + maxRemoteConnectionsPercentage, + randomPeerPriority, + bannedNodeIds, + allowedSubnets, + poaDiscoveryRetryBootnodes, + bootNodes, + discoveryDnsUrl); + } + + @Override + public List getCLIOptions() { + return CommandLineUtils.getCLIOptions(this, new P2PDiscoveryOptions()); + } +} diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/PermissionsOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/PermissionsOptions.java index f1eafaab165..4dc693d36ed 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/PermissionsOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/PermissionsOptions.java @@ -30,6 +30,7 @@ import picocli.CommandLine; /** Handles configuration options for permissions in Besu. */ +// TODO: implement CLIOption public class PermissionsOptions { @CommandLine.Option( names = {"--permissions-nodes-config-file-enabled"}, diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MetricsCLIOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MetricsCLIOptions.java index 95164c31cc6..4149d9869e2 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MetricsCLIOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MetricsCLIOptions.java @@ -23,6 +23,7 @@ import picocli.CommandLine; /** The Metrics cli options. */ +// TODO: combine into MetricsOptionGroup, use Unstable inner class pattern (see MiningOptions) public class MetricsCLIOptions implements CLIOptions { private static final String TIMERS_ENABLED_FLAG = "--Xmetrics-timers-enabled"; private static final String IDLE_TIMEOUT_FLAG = "--Xmetrics-idle-timeout"; diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/P2PTLSConfigOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/P2PTLSConfigOptions.java similarity index 99% rename from besu/src/main/java/org/hyperledger/besu/cli/options/stable/P2PTLSConfigOptions.java rename to besu/src/main/java/org/hyperledger/besu/cli/options/unstable/P2PTLSConfigOptions.java index c3f8c56219f..5939eb3d390 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/P2PTLSConfigOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/P2PTLSConfigOptions.java @@ -12,7 +12,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.hyperledger.besu.cli.options.stable; +package org.hyperledger.besu.cli.options.unstable; import static java.util.Arrays.asList; import static org.hyperledger.besu.cli.DefaultCommandValues.DEFAULT_KEYSTORE_TYPE; diff --git a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogHelper.java b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogHelper.java index 6bcfe4d3531..1ac309c430f 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogHelper.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogHelper.java @@ -15,11 +15,11 @@ package org.hyperledger.besu.cli.subcommands.storage; import static com.google.common.base.Preconditions.checkArgument; -import static org.hyperledger.besu.cli.options.stable.DataStorageOptions.BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD; +import static org.hyperledger.besu.cli.options.DataStorageOptions.BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD; import static org.hyperledger.besu.controller.BesuController.DATABASE_PATH; import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.DEFAULT_BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE; -import org.hyperledger.besu.cli.options.stable.DataStorageOptions; +import org.hyperledger.besu.cli.options.DataStorageOptions; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; diff --git a/besu/src/main/java/org/hyperledger/besu/components/BesuCommandModule.java b/besu/src/main/java/org/hyperledger/besu/components/BesuCommandModule.java index 59e2d60bf37..e757fd62a2b 100644 --- a/besu/src/main/java/org/hyperledger/besu/components/BesuCommandModule.java +++ b/besu/src/main/java/org/hyperledger/besu/components/BesuCommandModule.java @@ -20,7 +20,10 @@ import org.hyperledger.besu.chainimport.JsonBlockImporter; import org.hyperledger.besu.chainimport.RlpBlockImporter; import org.hyperledger.besu.cli.BesuCommand; +import org.hyperledger.besu.cli.options.stable.P2PDiscoveryOptions; +import org.hyperledger.besu.cli.options.unstable.RPCOptions; import org.hyperledger.besu.controller.BesuController; +import org.hyperledger.besu.ethereum.p2p.discovery.P2PDiscoveryConfiguration; import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; import org.hyperledger.besu.services.BesuPluginContextImpl; @@ -53,7 +56,6 @@ BesuCommand provideBesuCommand(final @Named("besuCommandLogger") Logger commandL new BesuPluginContextImpl(), System.getenv(), commandLogger); - besuCommand.toCommandLine(); return besuCommand; } @@ -63,6 +65,18 @@ MetricsConfiguration provideMetricsConfiguration(final BesuCommand provideFrom) return provideFrom.metricsConfiguration(); } + @Provides + @Singleton + RPCOptions provideRPCOptions() { + return RPCOptions.create(); + } + + @Provides + @Singleton + P2PDiscoveryConfiguration provideP2PDiscoveryConfiguration() { + return new P2PDiscoveryOptions().toDomainObject(); + } + @Provides @Named("besuCommandLogger") @Singleton diff --git a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java index 65e51c92139..7657dcd26ac 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java @@ -34,9 +34,9 @@ import org.hyperledger.besu.chainimport.JsonBlockImporter; import org.hyperledger.besu.chainimport.RlpBlockImporter; import org.hyperledger.besu.cli.config.EthNetworkConfig; +import org.hyperledger.besu.cli.options.DataStorageOptions; import org.hyperledger.besu.cli.options.MiningOptions; import org.hyperledger.besu.cli.options.TransactionPoolOptions; -import org.hyperledger.besu.cli.options.stable.DataStorageOptions; import org.hyperledger.besu.cli.options.stable.EthstatsOptions; import org.hyperledger.besu.cli.options.unstable.EthProtocolOptions; import org.hyperledger.besu.cli.options.unstable.MetricsCLIOptions; diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/stable/DataStorageOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/stable/DataStorageOptionsTest.java index 29fa3d66071..6be6429adb9 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/stable/DataStorageOptionsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/stable/DataStorageOptionsTest.java @@ -18,6 +18,7 @@ import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.MINIMUM_BONSAI_TRIE_LOG_RETENTION_LIMIT; import org.hyperledger.besu.cli.options.AbstractCLIOptionsTest; +import org.hyperledger.besu.cli.options.DataStorageOptions; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; diff --git a/config/src/main/java/org/hyperledger/besu/config/MergeConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/MergeConfigOptions.java index 53faf690521..6ba865e113e 100644 --- a/config/src/main/java/org/hyperledger/besu/config/MergeConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/MergeConfigOptions.java @@ -17,6 +17,8 @@ import java.util.concurrent.atomic.AtomicBoolean; /** The Merge config options. */ +// TODO: naming this with Options as the suffix is misleading, it should be MergeConfig - doesn't +// use picocli public class MergeConfigOptions { private static final AtomicBoolean mergeEnabled = new AtomicBoolean(false); diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/P2PDiscoveryConfiguration.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/P2PDiscoveryConfiguration.java new file mode 100644 index 00000000000..721a3100a07 --- /dev/null +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/P2PDiscoveryConfiguration.java @@ -0,0 +1,39 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.p2p.discovery; + +import org.hyperledger.besu.util.number.Percentage; + +import java.util.Collection; +import java.util.List; + +import org.apache.commons.net.util.SubnetUtils; +import org.apache.tuweni.bytes.Bytes; + +public record P2PDiscoveryConfiguration( + Boolean p2pEnabled, + Boolean peerDiscoveryEnabled, + String p2pHost, + String p2pInterface, + Integer p2pPort, + Integer maxPeers, + Boolean isLimitRemoteWireConnectionsEnabled, + Percentage maxRemoteConnectionsPercentage, + Boolean randomPeerPriority, + Collection bannedNodeIds, + List allowedSubnets, + Boolean poaDiscoveryRetryBootnodes, + List bootNodes, + String discoveryDnsUrl) {} From 8cf20ed7f5ece5f7b11127b1fdf917ee93d15179 Mon Sep 17 00:00:00 2001 From: Chaminda Divitotawela Date: Thu, 3 Oct 2024 12:07:19 +1000 Subject: [PATCH 2/8] Changes to release workflow (#7711) * Changes to release workflow - Workflow environment variable changed to RELEASE_VERSION instead of RELEASE_NAME to make it more meaningful - Workflows draft-release and docker-promote previously trigger workflow container-verify. This can result in trigger is successful but actual verification workflow fails. This will not be reflected in the draft-release and docker-promote workflows. Container verify code is embedded in the draft-release and docker-promote workflows to avoid this confusion Signed-off-by: Chaminda Divitotawela * PR comment improvements Signed-off-by: Chaminda Divitotawela * Match the only tags starting with word latest for latest check Signed-off-by: Chaminda Divitotawela --------- Signed-off-by: Chaminda Divitotawela Co-authored-by: Simon Dudley --- .github/workflows/BesuContainerVerify.sh | 2 +- .github/workflows/docker-promote.yml | 64 ++++++--- .github/workflows/draft-release.yml | 160 +++++++++++++---------- 3 files changed, 139 insertions(+), 87 deletions(-) diff --git a/.github/workflows/BesuContainerVerify.sh b/.github/workflows/BesuContainerVerify.sh index 81537f32648..1560de5c448 100644 --- a/.github/workflows/BesuContainerVerify.sh +++ b/.github/workflows/BesuContainerVerify.sh @@ -57,7 +57,7 @@ else fi # For the latest tag check the version match -if [[ ${TAG} == "latest" && ${CHECK_LATEST} == "true" ]] +if [[ ${TAG} =~ ^latest && ${CHECK_LATEST} == "true" ]] then _VERSION_IN_LOG=$(docker logs ${CONTAINER_NAME} | grep "#" | grep "Besu version" | cut -d " " -f 4 | sed 's/\s//g') echo "Extracted version from logs [$_VERSION_IN_LOG]" diff --git a/.github/workflows/docker-promote.yml b/.github/workflows/docker-promote.yml index 858ea7d20e8..18a3cc31703 100644 --- a/.github/workflows/docker-promote.yml +++ b/.github/workflows/docker-promote.yml @@ -14,25 +14,25 @@ jobs: validate: runs-on: ubuntu-22.04 env: - RELEASE_NAME: "${{ github.event.release.name }}" + RELEASE_VERSION: "${{ github.event.release.name }}" steps: - name: Pre-process Release Name - id: pre_process_release_name + id: pre_process_release_version run: | # strip all whitespace - RELEASE_NAME="${RELEASE_NAME//[[:space:]]/}" - if [[ ! "$RELEASE_NAME" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?(-.*)?$ ]]; then + RELEASE_VERSION="${RELEASE_VERSION//[[:space:]]/}" + if [[ ! "$RELEASE_VERSION" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?(-.*)?$ ]]; then echo "Release name does not conform to a valid besu release format YY.M.v[-suffix], e.g. 24.8.0-RC1." exit 1 fi - echo "release_name=$RELEASE_NAME" >> $GITHUB_OUTPUT # Set as output using the new syntax + echo "release_version=$RELEASE_VERSION" >> $GITHUB_OUTPUT # Set as output using the new syntax outputs: - release_name: ${{ steps.pre_process_release_name.outputs.release_name }} + release_version: ${{ steps.pre_process_release_version.outputs.release_version }} docker-promote: needs: [validate] env: - RELEASE_NAME: ${{ needs.validate.outputs.release_name }} # Use the output from the pre_process_release job + RELEASE_VERSION: ${{ needs.validate.outputs.release_version }} runs-on: ubuntu-22.04 steps: - name: Checkout @@ -58,24 +58,52 @@ jobs: cache-disabled: true - name: Docker upload - run: ./gradlew "-Prelease.releaseVersion=${{ env.RELEASE_NAME }}" "-PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }}" dockerUploadRelease + run: ./gradlew "-Prelease.releaseVersion=${{ env.RELEASE_VERSION }}" "-PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }}" dockerUploadRelease - name: Docker manifest - run: ./gradlew "-Prelease.releaseVersion=${{ env.RELEASE_NAME }}" "-PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }}" manifestDockerRelease + run: ./gradlew "-Prelease.releaseVersion=${{ env.RELEASE_VERSION }}" "-PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }}" manifestDockerRelease docker-verify: - needs: [validate, docker-promote] + needs: [validate,docker-promote] env: - RELEASE_NAME: ${{ needs.validate.outputs.release_name }} # Use the output from the pre_process_release job - runs-on: ubuntu-22.04 - permissions: - contents: read - actions: write + CONTAINER_NAME: besu-check + RELEASE_VERSION: ${{ needs.validate.outputs.release_version }} + runs-on: ${{ matrix.combination.runner }} + timeout-minutes: 4 + strategy: + matrix: + combination: + - tag: latest-amd64 + platform: 'linux/amd64' + runner: ubuntu-22.04 + - tag: latest + platform: '' + runner: ubuntu-22.04 + - tag: latest-arm64 + platform: '' + runner: besu-arm64 + - tag: latest + platform: '' + runner: besu-arm64 + steps: - name: Checkout uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + with: + sparse-checkout: '.github/workflows/BesuContainerVerify.sh' - - name: Trigger container verify - run: echo '{"version":"${{ env.RELEASE_NAME }}","verify-latest-version":"true"}' | gh workflow run container-verify.yml --json + - name: Start container + run: | + PLATFORM_OPT="" + [[ x${{ matrix.combination.platform }} != 'x' ]] && PLATFORM_OPT="--platform ${{ matrix.combination.platform }}" + docker run -d $PLATFORM_OPT --name ${{ env.CONTAINER_NAME }} ${{ secrets.DOCKER_ORG }}/besu:${{ matrix.combination.tag }} + + - name: Verify besu container + run: bash .github/workflows/BesuContainerVerify.sh env: - GH_TOKEN: ${{ github.token }} + TAG: ${{ matrix.combination.tag }} + VERSION: ${{ env.RELEASE_VERSION }} + CHECK_LATEST: true + + - name: Stop container + run: docker stop ${{ env.CONTAINER_NAME }} diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml index f6e01e1890e..8dc61bec461 100644 --- a/.github/workflows/draft-release.yml +++ b/.github/workflows/draft-release.yml @@ -16,7 +16,7 @@ jobs: validate: runs-on: ubuntu-22.04 env: - RELEASE_NAME: "${{ inputs.tag }}" + RELEASE_VERSION: "${{ inputs.tag }}" steps: - name: Check default branch run: | @@ -24,36 +24,36 @@ jobs: echo "Default Branch: ${{ github.event.repository.default_branch }}" if [[ ${{ github.ref_name }} != ${{ github.event.repository.default_branch }} ]] then - echo "This workflow can only be run on default branch" + echo "This workflow can only be run on default branch. This is not an issue for hot fixes as code is checked out from the tag" exit 1 fi - + - name: Pre-process Release Name - id: pre_process_release_name + id: validate_release_version run: | # strip all whitespace - RELEASE_NAME="${RELEASE_NAME//[[:space:]]/}" - if [[ ! "$RELEASE_NAME" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?(-.*)?$ ]]; then + RELEASE_VERSION="${RELEASE_VERSION//[[:space:]]/}" + if [[ ! "$RELEASE_VERSION" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?(-.*)?$ ]]; then echo "Release name does not conform to a valid besu release format YY.M.v[-suffix], e.g. 24.8.0-RC1." exit 1 fi - echo "release_name=$RELEASE_NAME" >> $GITHUB_OUTPUT # Set as output using the new syntax - + echo "release_version=$RELEASE_VERSION" >> $GITHUB_OUTPUT # Set as output using the new syntax + # Perform a tag checkout to ensure tag is available - name: Verify tag Exist uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - with: - ref: ${{ steps.pre_process_release_name.outputs.release_name }} + with: + ref: ${{ steps.validate_release_version.outputs.release_version }} fetch-depth: 1 outputs: - release_name: ${{ steps.pre_process_release_name.outputs.release_name }} + release_version: ${{ steps.validate_release_version.outputs.release_version }} build: runs-on: ubuntu-22.04 needs: validate env: - RELEASE_NAME: ${{ needs.validate.outputs.release_name }} # Use the output from the pre_process_release job + RELEASE_VERSION: ${{ needs.validate.outputs.release_version }} # Use the output from the pre_process_release job outputs: tarSha: ${{steps.hashes.outputs.tarSha}} zipSha: ${{steps.hashes.outputs.zipSha}} @@ -61,22 +61,22 @@ jobs: - name: Checkout tag uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 with: - ref: ${{ env.RELEASE_NAME }} - + ref: ${{ env.RELEASE_VERSION }} + - name: Set up Java uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 with: distribution: temurin java-version: 21 - + - name: Setup gradle uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1 with: cache-disabled: true - + - name: Assemble release run: - ./gradlew -Prelease.releaseVersion=${{env.RELEASE_NAME}} -Pversion=${{env.RELEASE_NAME}} assemble + ./gradlew -Prelease.releaseVersion=${{env.RELEASE_VERSION}} -Pversion=${{env.RELEASE_VERSION}} assemble - name: Hashes id: hashes @@ -86,35 +86,35 @@ jobs: echo "tarSha=$(shasum -a 256 besu*.tar.gz)" echo "zipSha=$(shasum -a 256 besu*.zip)" >> $GITHUB_OUTPUT echo "tarSha=$(shasum -a 256 besu*.tar.gz)" >> $GITHUB_OUTPUT - shasum -a 256 besu-${{env.RELEASE_NAME}}.tar.gz > besu-${{env.RELEASE_NAME}}.tar.gz.sha256 - shasum -a 256 besu-${{env.RELEASE_NAME}}.zip > besu-${{env.RELEASE_NAME}}.zip.sha256 - + shasum -a 256 besu-${{env.RELEASE_VERSION}}.tar.gz > besu-${{env.RELEASE_VERSION}}.tar.gz.sha256 + shasum -a 256 besu-${{env.RELEASE_VERSION}}.zip > besu-${{env.RELEASE_VERSION}}.zip.sha256 + - name: Upload tarball uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 with: - path: 'build/distributions/besu-${{ env.RELEASE_NAME }}.tar.gz' - name: besu-${{ env.RELEASE_NAME }}.tar.gz + path: 'build/distributions/besu-${{ env.RELEASE_VERSION }}.tar.gz' + name: besu-${{ env.RELEASE_VERSION }}.tar.gz compression-level: 0 - + - name: upload zipfile uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 with: - path: 'build/distributions/besu-${{ env.RELEASE_NAME }}.zip' - name: besu-${{ env.RELEASE_NAME }}.zip + path: 'build/distributions/besu-${{ env.RELEASE_VERSION }}.zip' + name: besu-${{ env.RELEASE_VERSION }}.zip compression-level: 0 - name: upload checksum zip uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 with: - path: 'build/distributions/besu-${{ env.RELEASE_NAME }}.zip.sha256' - name: besu-${{ env.RELEASE_NAME }}.zip.sha256 + path: 'build/distributions/besu-${{ env.RELEASE_VERSION }}.zip.sha256' + name: besu-${{ env.RELEASE_VERSION }}.zip.sha256 compression-level: 0 - name: upload checksum tar.gz uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 with: - path: 'build/distributions/besu-${{ env.RELEASE_NAME }}.tar.gz.sha256' - name: besu-${{ env.RELEASE_NAME }}.tar.gz.sha256 + path: 'build/distributions/besu-${{ env.RELEASE_VERSION }}.tar.gz.sha256' + name: besu-${{ env.RELEASE_VERSION }}.tar.gz.sha256 compression-level: 0 test-windows: @@ -127,7 +127,7 @@ jobs: with: distribution: temurin java-version: 21 - + - name: Download zip uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe with: @@ -153,7 +153,7 @@ jobs: with: distribution: temurin java-version: 21 - + - name: Download tar.gz uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe with: @@ -172,20 +172,20 @@ jobs: runs-on: ubuntu-22.04 needs: [test-linux, test-windows] env: - RELEASE_NAME: ${{ needs.validate.outputs.release_name }} # Use the output from the pre_process_release job + RELEASE_VERSION: ${{ needs.validate.outputs.release_version }} # Use the output from the pre_process_release job steps: - name: Checkout Repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 with: - ref: ${{ env.RELEASE_NAME }} + ref: ${{ env.RELEASE_VERSION }} - name: hadoLint run: docker run --rm -i hadolint/hadolint < docker/Dockerfile - + docker-publish: needs: [validate, docker-lint] env: - RELEASE_NAME: ${{ needs.validate.outputs.release_name }} # Use the output from the pre_process_release job + RELEASE_VERSION: ${{ needs.validate.outputs.release_version }} # Use the output from the pre_process_release job strategy: fail-fast: false matrix: @@ -198,7 +198,7 @@ jobs: id: prep run: | platform=${{ matrix.platform }} - if [ "$platform" = 'ubuntu-22.04' ]; then + if [ "$platform" = 'ubuntu-22.04' ]; then echo "PLATFORM_PAIR=linux-amd64" >> $GITHUB_OUTPUT echo "ARCH=amd64" >> $GITHUB_OUTPUT else @@ -209,7 +209,7 @@ jobs: - name: Checkout Repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 with: - ref: ${{ env.RELEASE_NAME }} + ref: ${{ env.RELEASE_VERSION }} - name: short sha id: shortSha @@ -225,7 +225,7 @@ jobs: uses: gradle/actions/setup-gradle@9e899d11ad247ec76be7a60bc1cf9d3abbb9e7f1 with: cache-disabled: true - + - name: install goss run: | mkdir -p docker/reports @@ -244,23 +244,23 @@ jobs: architecture: ${{ steps.prep.outputs.ARCH }} with: cache-disabled: true - arguments: testDocker -PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }} -Pversion=${{env.RELEASE_NAME}} -Prelease.releaseVersion=${{ env.RELEASE_NAME }} + arguments: testDocker -PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }} -Pversion=${{env.RELEASE_VERSION}} -Prelease.releaseVersion=${{ env.RELEASE_VERSION }} - name: publish env: architecture: ${{ steps.prep.outputs.ARCH }} - run: ./gradlew --no-daemon dockerUpload -PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }} -Pversion=${{env.RELEASE_NAME}} -Prelease.releaseVersion=${{ env.RELEASE_NAME }} + run: ./gradlew --no-daemon dockerUpload -PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }} -Pversion=${{env.RELEASE_VERSION}} -Prelease.releaseVersion=${{ env.RELEASE_VERSION }} docker-manifest: needs: [validate, docker-publish] runs-on: ubuntu-22.04 env: - RELEASE_NAME: ${{ needs.validate.outputs.release_name }} # Use the output from the pre_process_release job + RELEASE_VERSION: ${{ needs.validate.outputs.release_version }} steps: - name: Checkout Repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 with: - ref: ${{ env.RELEASE_NAME }} + ref: ${{ env.RELEASE_VERSION }} - name: Set up Java uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 @@ -281,24 +281,48 @@ jobs: password: ${{ secrets.DOCKER_PASSWORD_RW }} - name: multi-arch docker - run: ./gradlew manifestDocker -PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }} -Pversion=${{env.RELEASE_NAME}} -Prelease.releaseVersion=${{ env.RELEASE_NAME }} + run: ./gradlew manifestDocker -PdockerOrgName=${{ env.registry }}/${{ secrets.DOCKER_ORG }} -Pversion=${{env.RELEASE_VERSION}} -Prelease.releaseVersion=${{ env.RELEASE_VERSION }} docker-verify: needs: [validate,docker-manifest] env: - RELEASE_NAME: ${{ needs.validate.outputs.release_name }} # Use the output from the pre_process_release job - runs-on: ubuntu-22.04 - permissions: - contents: read - actions: write + CONTAINER_NAME: besu-check + RELEASE_VERSION: ${{ needs.validate.outputs.release_version }} + runs-on: ${{ matrix.combination.runner }} + timeout-minutes: 4 + strategy: + matrix: + combination: + - tag: ${{ needs.validate.outputs.release_version }} + platform: '' + runner: ubuntu-22.04 + - tag: ${{ needs.validate.outputs.release_version }}-amd64 + platform: 'linux/amd64' + runner: ubuntu-22.04 + - tag: ${{ needs.validate.outputs.release_version }}-arm64 + platform: '' + runner: besu-arm64 steps: - name: Checkout uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + with: + sparse-checkout: '.github/workflows/BesuContainerVerify.sh' + + - name: Start container + run: | + PLATFORM_OPT="" + [[ x${{ matrix.combination.platform }} != 'x' ]] && PLATFORM_OPT="--platform ${{ matrix.combination.platform }}" + docker run -d $PLATFORM_OPT --name ${{ env.CONTAINER_NAME }} ${{ secrets.DOCKER_ORG }}/besu:${{ matrix.combination.tag }} - - name: Trigger container verify - run: echo '{"version":"${{ env.RELEASE_NAME }}","verify-latest-version":"false"}' | gh workflow run container-verify.yml --json + - name: Verify besu container + run: bash .github/workflows/BesuContainerVerify.sh env: - GH_TOKEN: ${{ github.token }} + TAG: ${{ matrix.combination.tag }} + VERSION: ${{ env.RELEASE_VERSION }} + CHECK_LATEST: false + + - name: Stop container + run: docker stop ${{ env.CONTAINER_NAME }} release-draft: runs-on: ubuntu-22.04 @@ -306,42 +330,42 @@ jobs: permissions: contents: write env: - RELEASE_NAME: ${{ needs.validate.outputs.release_name }} + RELEASE_VERSION: ${{ needs.validate.outputs.release_version }} steps: - name: Checkout Repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 with: - ref: ${{ env.RELEASE_NAME }} + ref: ${{ env.RELEASE_VERSION }} - name: Download Besu artifacts uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe with: - pattern: besu-${{env.RELEASE_NAME}}* + pattern: besu-${{env.RELEASE_VERSION}}* merge-multiple: true - name: Draft release notes run: | - echo "## ${{env.RELEASE_NAME}}" > draft-release-notes.md + echo "## ${{env.RELEASE_VERSION}}" > draft-release-notes.md echo "## Upcoming Breaking Changes" >> draft-release-notes.md echo "## Breaking Changes" >> draft-release-notes.md echo "## Additions and Improvements" >> draft-release-notes.md echo "## Bug fixes" >> draft-release-notes.md - echo "`$(cat besu-${{env.RELEASE_NAME}}.zip.sha256)`" >> draft-release-notes.md - echo "`$(cat besu-${{env.RELEASE_NAME}}.tar.gz.sha256)`" >> draft-release-notes.md - cat besu-${{env.RELEASE_NAME}}.zip.sha256 >> draft-release-notes.md - cat besu-${{env.RELEASE_NAME}}.tar.gz.sha256 >> draft-release-notes.md + echo "`$(cat besu-${{env.RELEASE_VERSION}}.zip.sha256)`" >> draft-release-notes.md + echo "`$(cat besu-${{env.RELEASE_VERSION}}.tar.gz.sha256)`" >> draft-release-notes.md + cat besu-${{env.RELEASE_VERSION}}.zip.sha256 >> draft-release-notes.md + cat besu-${{env.RELEASE_VERSION}}.tar.gz.sha256 >> draft-release-notes.md - name: Draft release run: | gh release create \ --draft \ - --title=${{env.RELEASE_NAME}} \ + --title=${{env.RELEASE_VERSION}} \ --notes-file draft-release-notes.md \ - --verify-tag ${{env.RELEASE_NAME}} \ - besu-${{env.RELEASE_NAME}}.tar.gz \ - besu-${{env.RELEASE_NAME}}.zip \ - besu-${{env.RELEASE_NAME}}.zip.sha256 \ - besu-${{env.RELEASE_NAME}}.tar.gz.sha256 + --verify-tag ${{env.RELEASE_VERSION}} \ + besu-${{env.RELEASE_VERSION}}.tar.gz \ + besu-${{env.RELEASE_VERSION}}.zip \ + besu-${{env.RELEASE_VERSION}}.zip.sha256 \ + besu-${{env.RELEASE_VERSION}}.tar.gz.sha256 env: GH_TOKEN: ${{ github.token }} @@ -349,12 +373,12 @@ jobs: runs-on: ubuntu-22.04 needs: [validate, test-linux, test-windows] env: - RELEASE_NAME: ${{ needs.validate.outputs.release_name }} + RELEASE_VERSION: ${{ needs.validate.outputs.release_version }} steps: - name: checkout uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 with: - ref: ${{ env.RELEASE_NAME }} + ref: ${{ env.RELEASE_VERSION }} - name: Set up Java uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 @@ -371,4 +395,4 @@ jobs: env: ARTIFACTORY_USER: ${{ secrets.BESU_ARTIFACTORY_USER }} ARTIFACTORY_KEY: ${{ secrets.BESU_ARTIFACTORY_TOKEN }} - run: ./gradlew -Prelease.releaseVersion=${{ env.RELEASE_NAME }} -Pversion=${{env.RELEASE_NAME}} artifactoryPublish + run: ./gradlew -Prelease.releaseVersion=${{ env.RELEASE_VERSION }} -Pversion=${{env.RELEASE_VERSION}} artifactoryPublish From 63b9ec9daa80b17972596e2f39b6f6eff095889d Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 2 Oct 2024 20:52:46 -0600 Subject: [PATCH 3/8] ReturnDataLoad is an EOF only operation (#7670) Update ReturnDataLoadOperation to fail when called from legacy. Signed-off-by: Danno Ferrin --- .../besu/evm/operation/ReturnDataLoadOperation.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/ReturnDataLoadOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/ReturnDataLoadOperation.java index 7d8a5e42091..3c04b7b9398 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/ReturnDataLoadOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/ReturnDataLoadOperation.java @@ -16,6 +16,7 @@ import static org.hyperledger.besu.evm.internal.Words.clampedToInt; +import org.hyperledger.besu.evm.Code; import org.hyperledger.besu.evm.EVM; import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.gascalculator.GasCalculator; @@ -37,6 +38,11 @@ public ReturnDataLoadOperation(final GasCalculator gasCalculator) { @Override public OperationResult execute(final MessageFrame frame, final EVM evm) { + Code code = frame.getCode(); + if (code.getEofVersion() == 0) { + return InvalidOperation.INVALID_RESULT; + } + final int offset = clampedToInt(frame.popStackItem()); Bytes returnData = frame.getReturnData(); int retunDataSize = returnData.size(); From 49c6cbd1c32d46cea39ebd5d89804cf5204049ec Mon Sep 17 00:00:00 2001 From: Suyash Nayan <89125422+7suyash7@users.noreply.github.com> Date: Thu, 3 Oct 2024 12:43:34 +0530 Subject: [PATCH 4/8] return list in engine_getClientVersionV1 response (#7663) Signed-off-by: 7suyash7 Signed-off-by: Sally MacFarlane Co-authored-by: Sally MacFarlane --- .../methods/engine/EngineGetClientVersionV1.java | 12 ++++++++---- .../engine/EngineGetClientVersionV1Test.java | 15 +++++++++++++-- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetClientVersionV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetClientVersionV1.java index 149728186bc..011ce577a6e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetClientVersionV1.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetClientVersionV1.java @@ -22,6 +22,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetClientVersionResultV1; +import java.util.Collections; +import java.util.List; + import io.vertx.core.Vertx; public class EngineGetClientVersionV1 extends ExecutionEngineJsonRpcMethod { @@ -51,9 +54,10 @@ public String getName() { public JsonRpcResponse syncResponse(final JsonRpcRequestContext request) { String safeCommit = (commit != null && commit.length() >= 8) ? commit.substring(0, 8) : "unknown"; - return new JsonRpcSuccessResponse( - request.getRequest().getId(), - new EngineGetClientVersionResultV1( - ENGINE_CLIENT_CODE, ENGINE_CLIENT_NAME, clientVersion, safeCommit)); + List versions = + Collections.singletonList( + new EngineGetClientVersionResultV1( + ENGINE_CLIENT_CODE, ENGINE_CLIENT_NAME, clientVersion, safeCommit)); + return new JsonRpcSuccessResponse(request.getRequest().getId(), versions); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetClientVersionV1Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetClientVersionV1Test.java index 1aa0def7e27..d1d53832c13 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetClientVersionV1Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetClientVersionV1Test.java @@ -23,6 +23,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetClientVersionResultV1; +import java.util.List; + import io.vertx.core.Vertx; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -61,9 +63,18 @@ void testSyncResponse() { assertThat(actualResult).isInstanceOf(JsonRpcSuccessResponse.class); JsonRpcSuccessResponse successResponse = (JsonRpcSuccessResponse) actualResult; - assertThat(successResponse.getResult()).isInstanceOf(EngineGetClientVersionResultV1.class); + + assertThat(successResponse.getResult()).isInstanceOf(List.class); + + List resultList = (List) successResponse.getResult(); + assertThat(resultList).hasSize(1); + + Object firstElement = resultList.get(0); + assertThat(firstElement).isInstanceOf(EngineGetClientVersionResultV1.class); + EngineGetClientVersionResultV1 actualEngineGetClientVersionResultV1 = - (EngineGetClientVersionResultV1) successResponse.getResult(); + (EngineGetClientVersionResultV1) firstElement; + assertThat(actualEngineGetClientVersionResultV1.getName()).isEqualTo(ENGINE_CLIENT_NAME); assertThat(actualEngineGetClientVersionResultV1.getCode()).isEqualTo(ENGINE_CLIENT_CODE); assertThat(actualEngineGetClientVersionResultV1.getVersion()).isEqualTo(CLIENT_VERSION); From 911f12efa0039dbeb76606d57d6b0329589ad5a3 Mon Sep 17 00:00:00 2001 From: Justin Florentine Date: Thu, 3 Oct 2024 21:17:46 -0400 Subject: [PATCH 5/8] Repackage options (#7688) Updates MetricsOptions to implement CLIOptions, and to contain its unstable options. --------- Signed-off-by: Justin Florentine --- .../tests/acceptance/dsl/node/BesuNode.java | 4 +- .../org/hyperledger/besu/cli/BesuCommand.java | 62 +++++----- ...csOptionGroup.java => MetricsOptions.java} | 114 ++++++++++++++++-- .../options/stable/P2PDiscoveryOptions.java | 15 +-- .../options/unstable/MetricsCLIOptions.java | 80 ------------ .../hyperledger/besu/RunnerBuilderTest.java | 10 +- .../java/org/hyperledger/besu/RunnerTest.java | 6 +- .../chainimport/RlpBlockImporterTest.java | 4 +- .../hyperledger/besu/cli/BesuCommandTest.java | 6 +- .../besu/cli/CommandTestAbstract.java | 5 - ...tionsTest.java => MetricsOptionsTest.java} | 14 +-- ...igOptions.java => MergeConfiguration.java} | 8 +- .../BlockHeaderValidationRulesetFactory.java | 4 +- .../blockcreation/MergeCoordinatorTest.java | 4 +- .../merge/blockcreation/MergeReorgTest.java | 4 +- .../mainnet/MainnetBlockHeaderValidator.java | 4 +- .../prometheus/MetricsConfiguration.java | 8 +- 17 files changed, 172 insertions(+), 180 deletions(-) rename besu/src/main/java/org/hyperledger/besu/cli/options/stable/{MetricsOptionGroup.java => MetricsOptions.java} (57%) delete mode 100644 besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MetricsCLIOptions.java rename besu/src/test/java/org/hyperledger/besu/cli/options/{MetricsCLIOptionsTest.java => MetricsOptionsTest.java} (78%) rename config/src/main/java/org/hyperledger/besu/config/{MergeConfigOptions.java => MergeConfiguration.java} (85%) diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/BesuNode.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/BesuNode.java index 4e48be0401f..21ca45070bd 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/BesuNode.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/BesuNode.java @@ -18,7 +18,7 @@ import static org.apache.tuweni.io.file.Files.copyResource; import org.hyperledger.besu.cli.config.NetworkName; -import org.hyperledger.besu.config.MergeConfigOptions; +import org.hyperledger.besu.config.MergeConfiguration; import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.crypto.KeyPairUtil; import org.hyperledger.besu.datatypes.Address; @@ -228,7 +228,7 @@ public BesuNode( }); this.requestedPlugins = requestedPlugins; engineRpcConfiguration.ifPresent( - config -> MergeConfigOptions.setMergeEnabled(config.isEnabled())); + config -> MergeConfiguration.setMergeEnabled(config.isEnabled())); this.extraCLIOptions = extraCLIOptions; this.staticNodes = staticNodes; this.isDnsEnabled = isDnsEnabled; diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index fa59f48dd7b..d73c069f62c 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -50,7 +50,7 @@ import org.hyperledger.besu.cli.options.stable.GraphQlOptions; import org.hyperledger.besu.cli.options.stable.JsonRpcHttpOptions; import org.hyperledger.besu.cli.options.stable.LoggingLevelOption; -import org.hyperledger.besu.cli.options.stable.MetricsOptionGroup; +import org.hyperledger.besu.cli.options.stable.MetricsOptions; import org.hyperledger.besu.cli.options.stable.NodePrivateKeyFileOption; import org.hyperledger.besu.cli.options.stable.P2PDiscoveryOptions; import org.hyperledger.besu.cli.options.stable.PermissionsOptions; @@ -62,7 +62,6 @@ import org.hyperledger.besu.cli.options.unstable.EvmOptions; import org.hyperledger.besu.cli.options.unstable.InProcessRpcOptions; import org.hyperledger.besu.cli.options.unstable.IpcOptions; -import org.hyperledger.besu.cli.options.unstable.MetricsCLIOptions; import org.hyperledger.besu.cli.options.unstable.NatOptions; import org.hyperledger.besu.cli.options.unstable.NativeLibraryOptions; import org.hyperledger.besu.cli.options.unstable.NetworkingOptions; @@ -89,7 +88,7 @@ import org.hyperledger.besu.config.CheckpointConfigOptions; import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.config.GenesisConfigOptions; -import org.hyperledger.besu.config.MergeConfigOptions; +import org.hyperledger.besu.config.MergeConfiguration; import org.hyperledger.besu.controller.BesuController; import org.hyperledger.besu.controller.BesuControllerBuilder; import org.hyperledger.besu.crypto.Blake2bfMessageDigest; @@ -246,7 +245,6 @@ import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; import io.vertx.core.json.DecodeException; -import io.vertx.core.metrics.MetricsOptions; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; import org.slf4j.Logger; @@ -295,7 +293,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable { final NetworkingOptions unstableNetworkingOptions = NetworkingOptions.create(); final SynchronizerOptions unstableSynchronizerOptions = SynchronizerOptions.create(); final EthProtocolOptions unstableEthProtocolOptions = EthProtocolOptions.create(); - final MetricsCLIOptions unstableMetricsCLIOptions = MetricsCLIOptions.create(); private final DnsOptions unstableDnsOptions = DnsOptions.create(); private final NatOptions unstableNatOptions = NatOptions.create(); private final NativeLibraryOptions unstableNativeLibraryOptions = NativeLibraryOptions.create(); @@ -584,7 +581,7 @@ static class PrivacyOptionGroup { // Metrics Option Group @CommandLine.ArgGroup(validate = false, heading = "@|bold Metrics Options|@%n") - MetricsOptionGroup metricsOptionGroup = new MetricsOptionGroup(); + MetricsOptions metricsOptions = MetricsOptions.create(); @Option( names = {"--host-allowlist"}, @@ -1153,7 +1150,6 @@ private void handleUnstableOptions() { final ImmutableMap unstableOptions = unstableOptionsBuild .put("Ethereum Wire Protocol", unstableEthProtocolOptions) - .put("Metrics", unstableMetricsCLIOptions) .put("P2P Network", unstableNetworkingOptions) .put("RPC", unstableRPCOptions) .put("DNS Configuration", unstableDnsOptions) @@ -1864,7 +1860,7 @@ private void checkPrivacyTlsOptionsDependencies() { * @return instance of MetricsConfiguration. */ public MetricsConfiguration metricsConfiguration() { - if (metricsOptionGroup.getMetricsEnabled() && metricsOptionGroup.getMetricsPushEnabled()) { + if (metricsOptions.getMetricsEnabled() && metricsOptions.getMetricsPushEnabled()) { throw new ParameterException( this.commandLine, "--metrics-enabled option and --metrics-push-enabled option can't be used at the same " @@ -1875,40 +1871,33 @@ public MetricsConfiguration metricsConfiguration() { logger, commandLine, "--metrics-enabled", - !metricsOptionGroup.getMetricsEnabled(), + !metricsOptions.getMetricsEnabled(), asList("--metrics-host", "--metrics-port")); CommandLineUtils.checkOptionDependencies( logger, commandLine, "--metrics-push-enabled", - !metricsOptionGroup.getMetricsPushEnabled(), + !metricsOptions.getMetricsPushEnabled(), asList( "--metrics-push-host", "--metrics-push-port", "--metrics-push-interval", "--metrics-push-prometheus-job")); - return unstableMetricsCLIOptions - .toDomainObject() - .enabled(metricsOptionGroup.getMetricsEnabled()) + final MetricsConfiguration.Builder metricsConfigurationBuilder = + metricsOptions.toDomainObject(); + metricsConfigurationBuilder .host( - Strings.isNullOrEmpty(metricsOptionGroup.getMetricsHost()) + Strings.isNullOrEmpty(metricsOptions.getMetricsHost()) ? p2PDiscoveryOptions.p2pHost - : metricsOptionGroup.getMetricsHost()) - .port(metricsOptionGroup.getMetricsPort()) - .protocol(metricsOptionGroup.getMetricsProtocol()) - .metricCategories(metricsOptionGroup.getMetricCategories()) - .pushEnabled(metricsOptionGroup.getMetricsPushEnabled()) + : metricsOptions.getMetricsHost()) .pushHost( - Strings.isNullOrEmpty(metricsOptionGroup.getMetricsPushHost()) + Strings.isNullOrEmpty(metricsOptions.getMetricsPushHost()) ? p2PDiscoveryOptions.autoDiscoverDefaultIP().getHostAddress() - : metricsOptionGroup.getMetricsPushHost()) - .pushPort(metricsOptionGroup.getMetricsPushPort()) - .pushInterval(metricsOptionGroup.getMetricsPushInterval()) - .hostsAllowlist(hostsAllowlist) - .prometheusJob(metricsOptionGroup.getMetricsPrometheusJob()) - .build(); + : metricsOptions.getMetricsPushHost()) + .hostsAllowlist(hostsAllowlist); + return metricsConfigurationBuilder.build(); } private PrivacyParameters privacyParameters() { @@ -2281,7 +2270,7 @@ private VertxOptions createVertxOptions(final MetricsSystem metricsSystem) { return new VertxOptions() .setPreferNativeTransport(true) .setMetricsOptions( - new MetricsOptions() + new io.vertx.core.metrics.MetricsOptions() .setEnabled(true) .setFactory(new VertxMetricsAdapterFactory(metricsSystem))); } @@ -2537,9 +2526,7 @@ private List getEffectivePorts() { effectivePorts, rpcWebsocketOptions.getRpcWsPort(), rpcWebsocketOptions.isRpcWsEnabled()); addPortIfEnabled(effectivePorts, engineRPCConfig.engineRpcPort(), isEngineApiEnabled()); addPortIfEnabled( - effectivePorts, - metricsOptionGroup.getMetricsPort(), - metricsOptionGroup.getMetricsEnabled()); + effectivePorts, metricsOptions.getMetricsPort(), metricsOptions.getMetricsEnabled()); addPortIfEnabled( effectivePorts, miningParametersSupplier.get().getStratumPort(), @@ -2613,7 +2600,7 @@ protected GenesisConfigOptions getGenesisConfigOptions() { } private void setMergeConfigOptions() { - MergeConfigOptions.setMergeEnabled( + MergeConfiguration.setMergeEnabled( genesisConfigOptionsSupplier.get().getTerminalTotalDifficulty().isPresent()); } @@ -2658,7 +2645,7 @@ private void validatePostMergeCheckpointBlockRequirements() { } private boolean isMergeEnabled() { - return MergeConfigOptions.isMergeEnabled(); + return MergeConfiguration.isMergeEnabled(); } private boolean isEngineApiEnabled() { @@ -2752,11 +2739,20 @@ && getDataStorageConfiguration().getBonsaiLimitTrieLogsEnabled()) { } /** - * Returns the plugin context. + * 2 Returns the plugin context. * * @return the plugin context. */ public BesuPluginContextImpl getBesuPluginContext() { return besuPluginContext; } + + /** + * Returns the metrics options + * + * @return the metrics options + */ + public MetricsOptions getMetricsOptions() { + return metricsOptions; + } } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/MetricsOptionGroup.java b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/MetricsOptions.java similarity index 57% rename from besu/src/main/java/org/hyperledger/besu/cli/options/stable/MetricsOptionGroup.java rename to besu/src/main/java/org/hyperledger/besu/cli/options/stable/MetricsOptions.java index 1c17e1cf9dd..4906cf538e4 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/MetricsOptionGroup.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/MetricsOptions.java @@ -22,20 +22,80 @@ import static org.hyperledger.besu.metrics.prometheus.MetricsConfiguration.DEFAULT_METRICS_PORT; import static org.hyperledger.besu.metrics.prometheus.MetricsConfiguration.DEFAULT_METRICS_PUSH_PORT; +import org.hyperledger.besu.cli.options.CLIOptions; +import org.hyperledger.besu.cli.util.CommandLineUtils; import org.hyperledger.besu.metrics.MetricsProtocol; +import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; import org.hyperledger.besu.plugin.services.metrics.MetricCategory; +import java.util.List; import java.util.Set; import picocli.CommandLine; /** Command line options for configuring metrics. */ -// TODO: implement CLIOption and rename to drop the Group -public class MetricsOptionGroup { +// TODO: implement CLIOption +public class MetricsOptions implements CLIOptions { + + /** + * Returns a MetricsConfiguration.Builder because fields are often overridden from other domains, + * like using P2P settings as defaults. + * + * @return a newly created {@link MetricsOptions} with default values + */ + @Override + public MetricsConfiguration.Builder toDomainObject() { + MetricsConfiguration.Builder builder = MetricsConfiguration.builder(); + builder + .timersEnabled(unstableOptions.timersEnabled) + .idleTimeout(unstableOptions.idleTimeout) + .enabled(getMetricsEnabled()) + .host(getMetricsHost()) + .port(getMetricsPort()) + .protocol(getMetricsProtocol()) + .metricCategories(getMetricCategories()) + .pushEnabled(getMetricsPushEnabled()) + .pushHost(getMetricsPushHost()) + .pushPort(getMetricsPushPort()) + .pushInterval(getMetricsPushInterval()) + .prometheusJob(getMetricsPrometheusJob()); + return builder; + } + + // TODO: why do we need to be able to reverse this? + /** + * Returns a newly created {@link MetricsOptions} reversed from the supplied MetricsConfiguration + * + * @param config the metrics configuration + * @return a newly created {@link MetricsOptions} reversed from the supplied MetricsConfiguration + */ + public static MetricsOptions fromConfiguration(final MetricsConfiguration config) { + final MetricsOptions metricsOptions = create(); + metricsOptions.unstableOptions.timersEnabled = config.isTimersEnabled(); + metricsOptions.unstableOptions.idleTimeout = config.getIdleTimeout(); + metricsOptions.isMetricsEnabled = config.isEnabled(); + metricsOptions.metricsHost = config.getHost(); + metricsOptions.metricsPort = config.getPort(); + metricsOptions.metricsProtocol = config.getProtocol(); + metricsOptions.metricCategories = config.getMetricCategories(); + metricsOptions.metricsPrometheusJob = config.getPrometheusJob(); + metricsOptions.isMetricsPushEnabled = config.isPushEnabled(); + metricsOptions.metricsPushHost = config.getPushHost(); + metricsOptions.metricsPushPort = config.getPushPort(); + metricsOptions.metricsPushInterval = config.getPushInterval(); + + return metricsOptions; + } + + @Override + public List getCLIOptions() { + return CommandLineUtils.getCLIOptions(this, new MetricsOptions()); + } + @CommandLine.Option( names = {"--metrics-enabled"}, description = "Set to start the metrics exporter (default: ${DEFAULT-VALUE})") - private final Boolean isMetricsEnabled = false; + private Boolean isMetricsEnabled = false; @SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings. @CommandLine.Option( @@ -50,14 +110,14 @@ public class MetricsOptionGroup { paramLabel = MANDATORY_HOST_FORMAT_HELP, description = "Host for the metrics exporter to listen on (default: ${DEFAULT-VALUE})", arity = "1") - private String metricsHost; + private String metricsHost = MetricsConfiguration.DEFAULT_METRICS_HOST; @CommandLine.Option( names = {"--metrics-port"}, paramLabel = MANDATORY_PORT_FORMAT_HELP, description = "Port for the metrics exporter to listen on (default: ${DEFAULT-VALUE})", arity = "1") - private final Integer metricsPort = DEFAULT_METRICS_PORT; + private Integer metricsPort = DEFAULT_METRICS_PORT; @CommandLine.Option( names = {"--metrics-category", "--metrics-categories"}, @@ -66,12 +126,12 @@ public class MetricsOptionGroup { arity = "1..*", description = "Comma separated list of categories to track metrics for (default: ${DEFAULT-VALUE})") - private final Set metricCategories = DEFAULT_METRIC_CATEGORIES; + private Set metricCategories = DEFAULT_METRIC_CATEGORIES; @CommandLine.Option( names = {"--metrics-push-enabled"}, description = "Enable the metrics push gateway integration (default: ${DEFAULT-VALUE})") - private final Boolean isMetricsPushEnabled = false; + private Boolean isMetricsPushEnabled = false; @SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings. @CommandLine.Option( @@ -79,14 +139,14 @@ public class MetricsOptionGroup { paramLabel = MANDATORY_HOST_FORMAT_HELP, description = "Host of the Prometheus Push Gateway for push mode (default: ${DEFAULT-VALUE})", arity = "1") - private String metricsPushHost; + private String metricsPushHost = MetricsConfiguration.DEFAULT_METRICS_PUSH_HOST; @CommandLine.Option( names = {"--metrics-push-port"}, paramLabel = MANDATORY_PORT_FORMAT_HELP, description = "Port of the Prometheus Push Gateway for push mode (default: ${DEFAULT-VALUE})", arity = "1") - private final Integer metricsPushPort = DEFAULT_METRICS_PUSH_PORT; + private Integer metricsPushPort = DEFAULT_METRICS_PUSH_PORT; @CommandLine.Option( names = {"--metrics-push-interval"}, @@ -94,7 +154,7 @@ public class MetricsOptionGroup { description = "Interval in seconds to push metrics when in push mode (default: ${DEFAULT-VALUE})", arity = "1") - private final Integer metricsPushInterval = 15; + private Integer metricsPushInterval = 15; @SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings. @CommandLine.Option( @@ -103,8 +163,16 @@ public class MetricsOptionGroup { arity = "1") private String metricsPrometheusJob = "besu-client"; - /** Returns a newly created {@link MetricsOptionGroup} with default values. */ - public MetricsOptionGroup() {} + /** + * Returns a newly created {@link MetricsOptions} with default values. + * + * @return new instance + */ + public static MetricsOptions create() { + return new MetricsOptions(); + } + + private MetricsOptions() {} /** * Returns whether metrics are enabled. @@ -195,4 +263,26 @@ public Integer getMetricsPushInterval() { public String getMetricsPrometheusJob() { return metricsPrometheusJob; } + + @CommandLine.ArgGroup(validate = false) + private final MetricsOptions.Unstable unstableOptions = new MetricsOptions.Unstable(); + + static class Unstable { + private static final String TIMERS_ENABLED_FLAG = "--Xmetrics-timers-enabled"; + private static final String IDLE_TIMEOUT_FLAG = "--Xmetrics-idle-timeout"; + + @CommandLine.Option( + names = TIMERS_ENABLED_FLAG, + hidden = true, + description = "Whether to enable timer metrics (default: ${DEFAULT-VALUE}).") + private Boolean timersEnabled = MetricsConfiguration.DEFAULT_METRICS_TIMERS_ENABLED; + + @CommandLine.Option( + hidden = true, + names = {IDLE_TIMEOUT_FLAG}, + paramLabel = "", + description = "Timeout for metrics TCP connections, in seconds (default: ${DEFAULT-VALUE})", + arity = "1") + private int idleTimeout = MetricsConfiguration.DEFAULT_METRICS_IDLE_TIMEOUT_SECONDS; + } } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/P2PDiscoveryOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/P2PDiscoveryOptions.java index 21c24b3e278..a15be99dc74 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/P2PDiscoveryOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/P2PDiscoveryOptions.java @@ -52,20 +52,7 @@ public P2PDiscoveryOptions() {} arity = "1") public 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. + /** Boolean option to indicate if peers should be discovered. */ @CommandLine.Option( names = {"--discovery-enabled"}, description = "Enable P2P discovery (default: ${DEFAULT-VALUE})", diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MetricsCLIOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MetricsCLIOptions.java deleted file mode 100644 index 4149d9869e2..00000000000 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MetricsCLIOptions.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.cli.options.unstable; - -import org.hyperledger.besu.cli.options.CLIOptions; -import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; - -import java.util.Arrays; -import java.util.List; - -import picocli.CommandLine; - -/** The Metrics cli options. */ -// TODO: combine into MetricsOptionGroup, use Unstable inner class pattern (see MiningOptions) -public class MetricsCLIOptions implements CLIOptions { - private static final String TIMERS_ENABLED_FLAG = "--Xmetrics-timers-enabled"; - private static final String IDLE_TIMEOUT_FLAG = "--Xmetrics-idle-timeout"; - - @CommandLine.Option( - names = TIMERS_ENABLED_FLAG, - hidden = true, - description = "Whether to enable timer metrics (default: ${DEFAULT-VALUE}).") - private Boolean timersEnabled = MetricsConfiguration.DEFAULT_METRICS_TIMERS_ENABLED; - - @CommandLine.Option( - hidden = true, - names = {IDLE_TIMEOUT_FLAG}, - paramLabel = "", - description = "Timeout for metrics TCP connections, in seconds (default: ${DEFAULT-VALUE})", - arity = "1") - private int idleTimeout = MetricsConfiguration.DEFAULT_METRICS_IDLE_TIMEOUT_SECONDS; - - private MetricsCLIOptions() {} - - /** - * Create metrics cli options. - * - * @return the metrics cli options - */ - public static MetricsCLIOptions create() { - return new MetricsCLIOptions(); - } - - /** - * From configuration metrics cli options. - * - * @param config the config - * @return the metrics cli options - */ - public static MetricsCLIOptions fromConfiguration(final MetricsConfiguration config) { - final MetricsCLIOptions metricsOptions = create(); - metricsOptions.timersEnabled = config.isTimersEnabled(); - metricsOptions.idleTimeout = config.getIdleTimeout(); - return metricsOptions; - } - - @Override - public MetricsConfiguration.Builder toDomainObject() { - return MetricsConfiguration.builder().timersEnabled(timersEnabled).idleTimeout(idleTimeout); - } - - @Override - public List getCLIOptions() { - return Arrays.asList( - TIMERS_ENABLED_FLAG + "=" + timersEnabled.toString(), - IDLE_TIMEOUT_FLAG + "=" + idleTimeout); - } -} diff --git a/besu/src/test/java/org/hyperledger/besu/RunnerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/RunnerBuilderTest.java index c7180b958c1..7c5579d4711 100644 --- a/besu/src/test/java/org/hyperledger/besu/RunnerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/RunnerBuilderTest.java @@ -24,7 +24,7 @@ import org.hyperledger.besu.cli.config.EthNetworkConfig; import org.hyperledger.besu.config.GenesisConfigOptions; -import org.hyperledger.besu.config.MergeConfigOptions; +import org.hyperledger.besu.config.MergeConfiguration; import org.hyperledger.besu.consensus.common.bft.BftEventQueue; import org.hyperledger.besu.consensus.common.bft.network.PeerConnectionTracker; import org.hyperledger.besu.consensus.common.bft.protocol.BftProtocolManager; @@ -250,7 +250,7 @@ public void whenEngineApiAddedListensOnDefaultPort() { engine.setEnabled(true); final EthNetworkConfig mockMainnet = mock(EthNetworkConfig.class); when(mockMainnet.networkId()).thenReturn(BigInteger.ONE); - MergeConfigOptions.setMergeEnabled(true); + MergeConfiguration.setMergeEnabled(true); when(besuController.getMiningCoordinator()).thenReturn(mock(MergeMiningCoordinator.class)); final Runner runner = @@ -292,7 +292,7 @@ public void whenEngineApiAddedWebSocketReadyOnSamePort() { wsRpc.setEnabled(true); final EthNetworkConfig mockMainnet = mock(EthNetworkConfig.class); when(mockMainnet.networkId()).thenReturn(BigInteger.ONE); - MergeConfigOptions.setMergeEnabled(true); + MergeConfiguration.setMergeEnabled(true); when(besuController.getMiningCoordinator()).thenReturn(mock(MergeMiningCoordinator.class)); final JsonRpcConfiguration engineConf = JsonRpcConfiguration.createEngineDefault(); engineConf.setEnabled(true); @@ -335,7 +335,7 @@ public void whenEngineApiAddedEthSubscribeAvailable() { wsRpc.setEnabled(true); final EthNetworkConfig mockMainnet = mock(EthNetworkConfig.class); when(mockMainnet.networkId()).thenReturn(BigInteger.ONE); - MergeConfigOptions.setMergeEnabled(true); + MergeConfiguration.setMergeEnabled(true); when(besuController.getMiningCoordinator()).thenReturn(mock(MergeMiningCoordinator.class)); final JsonRpcConfiguration engineConf = JsonRpcConfiguration.createEngineDefault(); engineConf.setEnabled(true); @@ -383,7 +383,7 @@ public void noEngineApiNoServiceForMethods() { defaultWebSockConfig.setEnabled(true); final EthNetworkConfig mockMainnet = mock(EthNetworkConfig.class); when(mockMainnet.networkId()).thenReturn(BigInteger.ONE); - MergeConfigOptions.setMergeEnabled(true); + MergeConfiguration.setMergeEnabled(true); final Runner runner = new RunnerBuilder() diff --git a/besu/src/test/java/org/hyperledger/besu/RunnerTest.java b/besu/src/test/java/org/hyperledger/besu/RunnerTest.java index 5fefc7ef224..cbbf9804084 100644 --- a/besu/src/test/java/org/hyperledger/besu/RunnerTest.java +++ b/besu/src/test/java/org/hyperledger/besu/RunnerTest.java @@ -28,7 +28,7 @@ import org.hyperledger.besu.components.BesuComponent; import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.config.JsonUtil; -import org.hyperledger.besu.config.MergeConfigOptions; +import org.hyperledger.besu.config.MergeConfiguration; import org.hyperledger.besu.controller.BesuController; import org.hyperledger.besu.controller.MainnetBesuControllerBuilder; import org.hyperledger.besu.crypto.KeyPairUtil; @@ -151,7 +151,7 @@ public void getFixedNodes() { @Test public void fullSyncFromGenesis() throws Exception { // set merge flag to false, otherwise this test can fail if a merge test runs first - MergeConfigOptions.setMergeEnabled(false); + MergeConfiguration.setMergeEnabled(false); syncFromGenesis(SyncMode.FULL, getFastSyncGenesis()); } @@ -159,7 +159,7 @@ public void fullSyncFromGenesis() throws Exception { @Test public void fastSyncFromGenesis() throws Exception { // set merge flag to false, otherwise this test can fail if a merge test runs first - MergeConfigOptions.setMergeEnabled(false); + MergeConfiguration.setMergeEnabled(false); syncFromGenesis(SyncMode.FAST, getFastSyncGenesis()); } diff --git a/besu/src/test/java/org/hyperledger/besu/chainimport/RlpBlockImporterTest.java b/besu/src/test/java/org/hyperledger/besu/chainimport/RlpBlockImporterTest.java index 7d4fabb2225..2d9e587c3fa 100644 --- a/besu/src/test/java/org/hyperledger/besu/chainimport/RlpBlockImporterTest.java +++ b/besu/src/test/java/org/hyperledger/besu/chainimport/RlpBlockImporterTest.java @@ -21,7 +21,7 @@ import org.hyperledger.besu.cli.config.EthNetworkConfig; import org.hyperledger.besu.cli.config.NetworkName; import org.hyperledger.besu.components.BesuComponent; -import org.hyperledger.besu.config.MergeConfigOptions; +import org.hyperledger.besu.config.MergeConfiguration; import org.hyperledger.besu.controller.BesuController; import org.hyperledger.besu.cryptoservices.NodeKeyUtils; import org.hyperledger.besu.ethereum.GasLimitCalculator; @@ -91,7 +91,7 @@ public void blockImport() throws IOException { @Test public void blockImportRejectsBadPow() throws IOException { // set merge flag to false, otherwise this test can fail if a merge test runs first - MergeConfigOptions.setMergeEnabled(false); + MergeConfiguration.setMergeEnabled(false); final Path source = dataDir.resolve("badpow.blocks"); BlockTestUtil.writeBadPowBlocks(source); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index 99b45ada1b8..5bc4c9465d2 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -44,7 +44,7 @@ import org.hyperledger.besu.BesuInfo; import org.hyperledger.besu.cli.config.EthNetworkConfig; import org.hyperledger.besu.config.GenesisConfigFile; -import org.hyperledger.besu.config.MergeConfigOptions; +import org.hyperledger.besu.config.MergeConfiguration; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; @@ -162,13 +162,13 @@ public void setup() { // and ignore errors in case no trusted setup was already loaded } - MergeConfigOptions.setMergeEnabled(false); + MergeConfiguration.setMergeEnabled(false); } @AfterEach public void tearDown() { - MergeConfigOptions.setMergeEnabled(false); + MergeConfiguration.setMergeEnabled(false); } @Test diff --git a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java index 7657dcd26ac..00603bec876 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java @@ -39,7 +39,6 @@ import org.hyperledger.besu.cli.options.TransactionPoolOptions; import org.hyperledger.besu.cli.options.stable.EthstatsOptions; import org.hyperledger.besu.cli.options.unstable.EthProtocolOptions; -import org.hyperledger.besu.cli.options.unstable.MetricsCLIOptions; import org.hyperledger.besu.cli.options.unstable.NetworkingOptions; import org.hyperledger.besu.cli.options.unstable.SynchronizerOptions; import org.hyperledger.besu.components.BesuComponent; @@ -610,10 +609,6 @@ public DataStorageOptions getDataStorageOptions() { return dataStorageOptions; } - public MetricsCLIOptions getMetricsCLIOptions() { - return unstableMetricsCLIOptions; - } - public void close() { if (vertx != null) { final AtomicBoolean closed = new AtomicBoolean(false); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/MetricsCLIOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/MetricsOptionsTest.java similarity index 78% rename from besu/src/test/java/org/hyperledger/besu/cli/options/MetricsCLIOptionsTest.java rename to besu/src/test/java/org/hyperledger/besu/cli/options/MetricsOptionsTest.java index e88462216f4..992dcc437d4 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/MetricsCLIOptionsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/MetricsOptionsTest.java @@ -14,15 +14,15 @@ */ package org.hyperledger.besu.cli.options; -import org.hyperledger.besu.cli.options.unstable.MetricsCLIOptions; +import org.hyperledger.besu.cli.options.stable.MetricsOptions; import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) -public class MetricsCLIOptionsTest - extends AbstractCLIOptionsTest { +public class MetricsOptionsTest + extends AbstractCLIOptionsTest { @Override protected MetricsConfiguration.Builder createDefaultDomainObject() { @@ -37,13 +37,13 @@ protected MetricsConfiguration.Builder createCustomizedDomainObject() { } @Override - protected MetricsCLIOptions optionsFromDomainObject( + protected MetricsOptions optionsFromDomainObject( final MetricsConfiguration.Builder domainObject) { - return MetricsCLIOptions.fromConfiguration(domainObject.build()); + return MetricsOptions.fromConfiguration(domainObject.build()); } @Override - protected MetricsCLIOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { - return besuCommand.getMetricsCLIOptions(); + protected MetricsOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { + return besuCommand.getMetricsOptions(); } } diff --git a/config/src/main/java/org/hyperledger/besu/config/MergeConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/MergeConfiguration.java similarity index 85% rename from config/src/main/java/org/hyperledger/besu/config/MergeConfigOptions.java rename to config/src/main/java/org/hyperledger/besu/config/MergeConfiguration.java index 6ba865e113e..5ab64442093 100644 --- a/config/src/main/java/org/hyperledger/besu/config/MergeConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/MergeConfiguration.java @@ -16,14 +16,14 @@ import java.util.concurrent.atomic.AtomicBoolean; -/** The Merge config options. */ -// TODO: naming this with Options as the suffix is misleading, it should be MergeConfig - doesn't +/** The Merge configuration. */ + // use picocli -public class MergeConfigOptions { +public class MergeConfiguration { private static final AtomicBoolean mergeEnabled = new AtomicBoolean(false); /** Default constructor. */ - private MergeConfigOptions() {} + private MergeConfiguration() {} /** * Enables merge. diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/BlockHeaderValidationRulesetFactory.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/BlockHeaderValidationRulesetFactory.java index 0274736c0fa..563f31f597c 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/BlockHeaderValidationRulesetFactory.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/BlockHeaderValidationRulesetFactory.java @@ -17,7 +17,7 @@ import static org.hyperledger.besu.ethereum.mainnet.AbstractGasLimitSpecification.DEFAULT_MAX_GAS_LIMIT; import static org.hyperledger.besu.ethereum.mainnet.AbstractGasLimitSpecification.DEFAULT_MIN_GAS_LIMIT; -import org.hyperledger.besu.config.MergeConfigOptions; +import org.hyperledger.besu.config.MergeConfiguration; import org.hyperledger.besu.consensus.clique.headervalidationrules.CliqueDifficultyValidationRule; import org.hyperledger.besu.consensus.clique.headervalidationrules.CliqueExtraDataValidationRule; import org.hyperledger.besu.consensus.clique.headervalidationrules.CliqueNoEmptyBlockValidationRule; @@ -69,7 +69,7 @@ public static BlockHeaderValidator.Builder cliqueBlockHeaderValidator( createEmptyBlocks, epochManager, baseFeeMarket, - MergeConfigOptions.isMergeEnabled()); + MergeConfiguration.isMergeEnabled()); } /** diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java index 9c1a3df075e..09c1b28af40 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java @@ -32,7 +32,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import org.hyperledger.besu.config.MergeConfigOptions; +import org.hyperledger.besu.config.MergeConfiguration; import org.hyperledger.besu.consensus.merge.MergeContext; import org.hyperledger.besu.consensus.merge.PayloadWrapper; import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator.ForkchoiceResult; @@ -204,7 +204,7 @@ public void setUp() { return blockCreationTask; }); - MergeConfigOptions.setMergeEnabled(true); + MergeConfiguration.setMergeEnabled(true); when(ethContext.getEthPeers().subscribeConnect(any())).thenReturn(1L); this.transactionPool = diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java index 9b6cf907d2b..7b111268e0f 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java @@ -19,7 +19,7 @@ import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryWorldStateArchive; import static org.mockito.Mockito.mock; -import org.hyperledger.besu.config.MergeConfigOptions; +import org.hyperledger.besu.config.MergeConfiguration; import org.hyperledger.besu.consensus.merge.MergeContext; import org.hyperledger.besu.consensus.merge.PostMergeContext; import org.hyperledger.besu.datatypes.Address; @@ -89,7 +89,7 @@ public void setUp() { genesisState.writeStateTo(mutable); mutable.persist(null); mergeContext.setTerminalTotalDifficulty(Difficulty.of(1001)); - MergeConfigOptions.setMergeEnabled(true); + MergeConfiguration.setMergeEnabled(true); this.coordinator = new MergeCoordinator( protocolContext, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java index 5f1fdff0f42..0598c817bd0 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.mainnet; -import org.hyperledger.besu.config.MergeConfigOptions; +import org.hyperledger.besu.config.MergeConfiguration; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; @@ -130,7 +130,7 @@ public static BlockHeaderValidator.Builder createPgaBlockHeaderValidator( public static BlockHeaderValidator.Builder createBaseFeeMarketValidator( final BaseFeeMarket baseFeeMarket) { - return createBaseFeeMarketValidator(baseFeeMarket, MergeConfigOptions.isMergeEnabled()); + return createBaseFeeMarketValidator(baseFeeMarket, MergeConfiguration.isMergeEnabled()); } @VisibleForTesting diff --git a/metrics/core/src/main/java/org/hyperledger/besu/metrics/prometheus/MetricsConfiguration.java b/metrics/core/src/main/java/org/hyperledger/besu/metrics/prometheus/MetricsConfiguration.java index 4a542fce00b..d32823630ba 100644 --- a/metrics/core/src/main/java/org/hyperledger/besu/metrics/prometheus/MetricsConfiguration.java +++ b/metrics/core/src/main/java/org/hyperledger/besu/metrics/prometheus/MetricsConfiguration.java @@ -30,13 +30,17 @@ /** The Metrics configuration. */ public class MetricsConfiguration { - private static final String DEFAULT_METRICS_HOST = "127.0.0.1"; + + /** The constant DEFAULT_METRICS_HOST. */ + public static final String DEFAULT_METRICS_HOST = "127.0.0.1"; /** The constant DEFAULT_METRICS_PORT. */ public static final int DEFAULT_METRICS_PORT = 9545; private static final MetricsProtocol DEFAULT_METRICS_PROTOCOL = MetricsProtocol.PROMETHEUS; - private static final String DEFAULT_METRICS_PUSH_HOST = "127.0.0.1"; + + /** The constant DEFAULT_METRICS_PUSH_HOST. */ + public static final String DEFAULT_METRICS_PUSH_HOST = "127.0.0.1"; /** The constant DEFAULT_METRICS_PUSH_PORT. */ public static final int DEFAULT_METRICS_PUSH_PORT = 9001; From 67d738c8a111716542854d784f48f36587412a9c Mon Sep 17 00:00:00 2001 From: Glory Agatevure Date: Fri, 4 Oct 2024 02:40:48 +0100 Subject: [PATCH 6/8] Add ephemery network config (#7563) * Add Ephemery genesis config file Signed-off-by: gconnect --------- Signed-off-by: gconnect Signed-off-by: Glory Agatevure Co-authored-by: Sally MacFarlane --- CHANGELOG.md | 3 +- .../org/hyperledger/besu/cli/BesuCommand.java | 21 +- .../besu/cli/config/EthNetworkConfig.java | 1 + .../besu/cli/config/NetworkName.java | 6 + .../besu/util/EphemeryGenesisUpdater.java | 81 ++ .../hyperledger/besu/cli/BesuCommandTest.java | 16 + .../cli/NetworkDeprecationMessageTest.java | 4 +- .../besu/util/EphemeryGenesisUpdaterTest.java | 139 +++ .../besu/config/GenesisConfigFile.java | 3 + config/src/main/resources/ephemery.json | 916 ++++++++++++++++++ 10 files changed, 1180 insertions(+), 10 deletions(-) create mode 100644 besu/src/main/java/org/hyperledger/besu/util/EphemeryGenesisUpdater.java create mode 100644 besu/src/test/java/org/hyperledger/besu/util/EphemeryGenesisUpdaterTest.java create mode 100644 config/src/main/resources/ephemery.json diff --git a/CHANGELOG.md b/CHANGELOG.md index cb965bfb107..e304b72632f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog ## [Unreleased] +- Add `--ephemery` network support for Ephemery Testnet [#7563](https://github.com/hyperledger/besu/pull/7563) thanks to [@gconnect](https://github.com/gconnect) +- Add configuration of Consolidation Request Contract Address via genesis configuration [#7647](https://github.com/hyperledger/besu/pull/7647) ### Upcoming Breaking Changes - k8s (KUBERNETES) Nat method is now deprecated and will be removed in a future release @@ -4461,7 +4463,6 @@ Specify `*` or `all` for `--host-whitelist` to effectively disable host protecti - Send client quitting disconnect message to peers on shutdown (PR [#253](https://github.com/PegaSysEng/pantheon/pull/253)) - Improved error message for port conflict error (PR [#232](https://github.com/PegaSysEng/pantheon/pull/232)) - ### Technical Improvements - Upgraded Ethereum reference tests to 6.0 beta 2. (thanks to [@jvirtanen](https://github.com/jvirtanen) for the initial upgrade to beta 1) - Set Java compiler default encoding to UTF-8 (PR [#238](https://github.com/PegaSysEng/pantheon/pull/238) thanks to [@matt9ucci](https://github.com/matt9ucci)) diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index d73c069f62c..41402fa04b3 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -20,6 +20,7 @@ import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static org.hyperledger.besu.cli.DefaultCommandValues.getDefaultBesuDataPath; +import static org.hyperledger.besu.cli.config.NetworkName.EPHEMERY; import static org.hyperledger.besu.cli.config.NetworkName.MAINNET; import static org.hyperledger.besu.cli.util.CommandLineUtils.DEPENDENCY_WARNING_MSG; import static org.hyperledger.besu.cli.util.CommandLineUtils.isOptionSet; @@ -195,6 +196,7 @@ import org.hyperledger.besu.services.TransactionSelectionServiceImpl; import org.hyperledger.besu.services.TransactionSimulationServiceImpl; import org.hyperledger.besu.services.kvstore.InMemoryStoragePlugin; +import org.hyperledger.besu.util.EphemeryGenesisUpdater; import org.hyperledger.besu.util.InvalidConfigurationException; import org.hyperledger.besu.util.LogConfigurator; import org.hyperledger.besu.util.NetworkUtility; @@ -1602,11 +1604,14 @@ private void validateChainDataPruningParams() { } private GenesisConfigFile readGenesisConfigFile() { - final GenesisConfigFile effectiveGenesisFile = - genesisFile != null - ? GenesisConfigFile.fromSource(genesisConfigSource(genesisFile)) - : GenesisConfigFile.fromResource( - Optional.ofNullable(network).orElse(MAINNET).getGenesisFile()); + GenesisConfigFile effectiveGenesisFile; + effectiveGenesisFile = + network.equals(EPHEMERY) + ? EphemeryGenesisUpdater.updateGenesis(genesisConfigOverrides) + : genesisFile != null + ? GenesisConfigFile.fromSource(genesisConfigSource(genesisFile)) + : GenesisConfigFile.fromResource( + Optional.ofNullable(network).orElse(MAINNET).getGenesisFile()); return effectiveGenesisFile.withOverrides(genesisConfigOverrides); } @@ -2333,7 +2338,11 @@ private EthNetworkConfig updateNetworkConfig(final NetworkName network) { if (networkId != null) { builder.setNetworkId(networkId); } - + // ChainId update is required for Ephemery network + if (network.equals(EPHEMERY)) { + String chainId = genesisConfigOverrides.get("chainId"); + builder.setNetworkId(new BigInteger(chainId)); + } if (p2PDiscoveryOptions.discoveryDnsUrl != null) { builder.setDnsDiscoveryUrl(p2PDiscoveryOptions.discoveryDnsUrl); } else { diff --git a/besu/src/main/java/org/hyperledger/besu/cli/config/EthNetworkConfig.java b/besu/src/main/java/org/hyperledger/besu/cli/config/EthNetworkConfig.java index dd5e43e63fe..dab3a4c227c 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/config/EthNetworkConfig.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/config/EthNetworkConfig.java @@ -77,6 +77,7 @@ public static EthNetworkConfig getNetworkConfig(final NetworkName networkName) { strings -> strings.stream().map(EnodeURLImpl::fromString).collect(Collectors.toList())) .orElse(Collections.emptyList()); + return new EthNetworkConfig( genesisConfigFile, networkName.getNetworkId(), diff --git a/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java b/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java index f864068bb4e..9cb5296d32f 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java @@ -31,6 +31,12 @@ public enum NetworkName { /** LUKSO mainnet network name. */ LUKSO("/lukso.json", BigInteger.valueOf(42)), + /** + * EPHEMERY network name. The actual networkId used is calculated based on this default value and + * the current time. https://ephemery.dev/ + */ + EPHEMERY("/ephemery.json", BigInteger.valueOf(39438135)), + /** Dev network name. */ DEV("/dev.json", BigInteger.valueOf(2018), false), /** Future EIPs network name. */ diff --git a/besu/src/main/java/org/hyperledger/besu/util/EphemeryGenesisUpdater.java b/besu/src/main/java/org/hyperledger/besu/util/EphemeryGenesisUpdater.java new file mode 100644 index 00000000000..0b970a6809c --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/util/EphemeryGenesisUpdater.java @@ -0,0 +1,81 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.util; + +import static org.hyperledger.besu.cli.config.NetworkName.EPHEMERY; + +import org.hyperledger.besu.config.GenesisConfigFile; + +import java.io.IOException; +import java.math.BigInteger; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Map; +import java.util.Optional; + +/** + * The Generate Ephemery Genesis Updater. Checks for update based on the set period and update the + * Ephemery genesis in memory + */ +public class EphemeryGenesisUpdater { + private static final int PERIOD_IN_DAYS = 28; + private static final long PERIOD_IN_SECONDS = (PERIOD_IN_DAYS * 24 * 60 * 60); + + /** + * Constructor for EphemeryGenesisUpdater. Initializes the genesis updater for the Ephemery + * network. + */ + public EphemeryGenesisUpdater() {} + + /** + * Updates the Ephemery genesis configuration based on the predefined period. + * + * @param overrides a map of configuration overrides + * @return the updated GenesisConfigFile + * @throws RuntimeException if an error occurs during the update process + */ + public static GenesisConfigFile updateGenesis(final Map overrides) + throws RuntimeException { + GenesisConfigFile genesisConfigFile; + try { + if (EPHEMERY.getGenesisFile() == null) { + throw new IOException("Genesis file or config options are null"); + } + genesisConfigFile = GenesisConfigFile.fromResource(EPHEMERY.getGenesisFile()); + long genesisTimestamp = genesisConfigFile.getTimestamp(); + Optional genesisChainId = genesisConfigFile.getConfigOptions().getChainId(); + long currentTimestamp = Instant.now().getEpochSecond(); + long periodsSinceGenesis = + ChronoUnit.DAYS.between(Instant.ofEpochSecond(genesisTimestamp), Instant.now()) + / PERIOD_IN_DAYS; + + long updatedTimestamp = genesisTimestamp + (periodsSinceGenesis * PERIOD_IN_SECONDS); + BigInteger updatedChainId = + genesisChainId + .orElseThrow(() -> new IllegalStateException("ChainId not present")) + .add(BigInteger.valueOf(periodsSinceGenesis)); + // has a period elapsed since original ephemery genesis time? if so, override chainId and + // timestamp + if (currentTimestamp > (genesisTimestamp + PERIOD_IN_SECONDS)) { + overrides.put("chainId", String.valueOf(updatedChainId)); + overrides.put("timestamp", String.valueOf(updatedTimestamp)); + genesisConfigFile = genesisConfigFile.withOverrides(overrides); + } + return genesisConfigFile.withOverrides(overrides); + } catch (IOException e) { + throw new RuntimeException("Error updating ephemery genesis: " + e.getMessage(), e); + } + } +} diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index 5bc4c9465d2..d63ffef7fa6 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -19,6 +19,7 @@ import static org.hamcrest.Matchers.is; import static org.hyperledger.besu.cli.config.NetworkName.CLASSIC; import static org.hyperledger.besu.cli.config.NetworkName.DEV; +import static org.hyperledger.besu.cli.config.NetworkName.EPHEMERY; import static org.hyperledger.besu.cli.config.NetworkName.EXPERIMENTAL_EIPS; import static org.hyperledger.besu.cli.config.NetworkName.FUTURE_EIPS; import static org.hyperledger.besu.cli.config.NetworkName.HOLESKY; @@ -43,6 +44,7 @@ import org.hyperledger.besu.BesuInfo; import org.hyperledger.besu.cli.config.EthNetworkConfig; +import org.hyperledger.besu.cli.config.NetworkName; import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.config.MergeConfiguration; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; @@ -1863,6 +1865,20 @@ public void luksoValuesAreUsed() { assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); } + @Test + public void ephemeryValuesAreUsed() { + parseCommand("--network", "ephemery"); + + final ArgumentCaptor networkArg = + ArgumentCaptor.forClass(EthNetworkConfig.class); + + verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any()); + verify(mockControllerBuilder).build(); + assertThat(NetworkName.valueOf(String.valueOf(EPHEMERY))).isEqualTo(EPHEMERY); + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + } + @Test public void classicValuesAreUsed() { parseCommand("--network", "classic"); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/NetworkDeprecationMessageTest.java b/besu/src/test/java/org/hyperledger/besu/cli/NetworkDeprecationMessageTest.java index 87be2a699e3..649560d1119 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/NetworkDeprecationMessageTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/NetworkDeprecationMessageTest.java @@ -39,9 +39,7 @@ void shouldGenerateDeprecationMessageForDeprecatedNetworks(final NetworkName net @ParameterizedTest @EnumSource( value = NetworkName.class, - names = { - "MAINNET", "SEPOLIA", "DEV", "CLASSIC", "MORDOR", "HOLESKY", "LUKSO", - }) + names = {"MAINNET", "SEPOLIA", "DEV", "CLASSIC", "MORDOR", "HOLESKY", "LUKSO", "EPHEMERY"}) void shouldThrowErrorForNonDeprecatedNetworks(final NetworkName network) { assertThatThrownBy(() -> NetworkDeprecationMessage.generate(network)) .isInstanceOf(AssertionError.class); diff --git a/besu/src/test/java/org/hyperledger/besu/util/EphemeryGenesisUpdaterTest.java b/besu/src/test/java/org/hyperledger/besu/util/EphemeryGenesisUpdaterTest.java new file mode 100644 index 00000000000..fe21c1e6d72 --- /dev/null +++ b/besu/src/test/java/org/hyperledger/besu/util/EphemeryGenesisUpdaterTest.java @@ -0,0 +1,139 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.util; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.hyperledger.besu.config.GenesisConfigFile.fromConfig; + +import org.hyperledger.besu.config.GenesisConfigFile; + +import java.math.BigInteger; +import java.util.Map; +import java.util.Optional; +import java.util.TreeMap; + +import io.vertx.core.json.JsonObject; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class EphemeryGenesisUpdaterTest { + private static final int GENESIS_CONFIG_TEST_CHAINID = 39438135; + private static final long GENESIS_TEST_TIMESTAMP = 1720119600; + private static final long EARLIER_TIMESTAMP = 1712041200; + private static final long LATER_TIMESTAMP = 1922041200; + private static final long PERIOD_IN_SECONDS = 28 * 24 * 60 * 60; + private static final long PERIOD_SINCE_GENESIS = 3; + + private static final JsonObject VALID_GENESIS_JSON = + (new JsonObject()) + .put("config", (new JsonObject()).put("chainId", GENESIS_CONFIG_TEST_CHAINID)) + .put("timestamp", GENESIS_TEST_TIMESTAMP); + + private static final GenesisConfigFile INVALID_GENESIS_JSON = fromConfig("{}"); + private static final JsonObject INVALID_GENESIS_JSON_WITHOUT_CHAINID = + (new JsonObject()).put("timestamp", GENESIS_TEST_TIMESTAMP); + + private static final JsonObject INVALID_GENESIS_JSON_WITHOUT_TIMESTAMP = + new JsonObject() + .put("config", (new JsonObject()).put("chainId", GENESIS_CONFIG_TEST_CHAINID)); + + @Test + public void testEphemeryWhenChainIdIsAbsent() { + final GenesisConfigFile config = + GenesisConfigFile.fromConfig(INVALID_GENESIS_JSON_WITHOUT_CHAINID.toString()); + Optional chainId = config.getConfigOptions().getChainId(); + assertThat(chainId).isNotPresent(); + } + + @Test + public void testShouldDefaultTimestampToZero() { + final GenesisConfigFile config = + GenesisConfigFile.fromConfig(INVALID_GENESIS_JSON_WITHOUT_TIMESTAMP.toString()); + assertThat(config.getTimestamp()).isZero(); + } + + @Test + public void testEphemeryWhenGenesisJsonIsInvalid() { + assertThatThrownBy(INVALID_GENESIS_JSON::getDifficulty) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid genesis block configuration"); + } + + @Test + public void testEphemeryWhenGenesisJsonIsValid() { + final GenesisConfigFile config = GenesisConfigFile.fromConfig(VALID_GENESIS_JSON.toString()); + assertThat(String.valueOf(config.getTimestamp())) + .isEqualTo(String.valueOf(GENESIS_TEST_TIMESTAMP)); + assertThat(config.getConfigOptions().getChainId()) + .hasValue(BigInteger.valueOf(GENESIS_CONFIG_TEST_CHAINID)); + assertThat(String.valueOf(config.getTimestamp())).isNotNull(); + assertThat(String.valueOf(config.getTimestamp())).isNotEmpty(); + } + + @Test + public void testEphemeryNotYetDueForUpdate() { + final GenesisConfigFile config = GenesisConfigFile.fromConfig(VALID_GENESIS_JSON.toString()); + assertThat(EARLIER_TIMESTAMP).isLessThan(config.getTimestamp() + PERIOD_IN_SECONDS); + } + + @Test + void testOverrideWithUpdatedChainIdAndTimeStamp() { + BigInteger expectedChainId = + BigInteger.valueOf(GENESIS_CONFIG_TEST_CHAINID) + .add(BigInteger.valueOf(PERIOD_SINCE_GENESIS)); + + long expectedGenesisTimestamp = + GENESIS_TEST_TIMESTAMP + (PERIOD_SINCE_GENESIS * PERIOD_IN_SECONDS); + + final GenesisConfigFile config = GenesisConfigFile.fromResource("/ephemery.json"); + + final Map override = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + override.put("chainId", String.valueOf(expectedChainId)); + override.put("timestamp", String.valueOf(expectedGenesisTimestamp)); + + assertThat(config.withOverrides(override).getConfigOptions().getChainId()).isPresent(); + assertThat(config.withOverrides(override).getConfigOptions().getChainId()) + .hasValue(expectedChainId); + assertThat(config.withOverrides(override).getTimestamp()).isNotNull(); + assertThat(expectedChainId).isEqualTo(override.get("chainId")); + assertThat(String.valueOf(expectedGenesisTimestamp)).isEqualTo(override.get("timestamp")); + } + + @Test + public void testEphemeryWhenSuccessful() { + final GenesisConfigFile config = GenesisConfigFile.fromConfig(VALID_GENESIS_JSON.toString()); + + BigInteger expectedChainId = + BigInteger.valueOf(GENESIS_CONFIG_TEST_CHAINID) + .add(BigInteger.valueOf(PERIOD_SINCE_GENESIS)); + + long expectedGenesisTimestamp = + GENESIS_TEST_TIMESTAMP + (PERIOD_SINCE_GENESIS * PERIOD_IN_SECONDS); + final Map override = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + override.put("chainId", String.valueOf(expectedChainId)); + override.put("timestamp", String.valueOf(expectedGenesisTimestamp)); + final GenesisConfigFile updatedConfig = config.withOverrides(override); + + assertThat(LATER_TIMESTAMP) + .isGreaterThan(Long.parseLong(String.valueOf(GENESIS_TEST_TIMESTAMP + PERIOD_IN_SECONDS))); + assertThat(updatedConfig.getConfigOptions().getChainId()).hasValue(expectedChainId); + assertThat(updatedConfig.getTimestamp()).isEqualTo(expectedGenesisTimestamp); + assertThat(override.get("timestamp")).isEqualTo(String.valueOf(expectedGenesisTimestamp)); + assertThat(override.get("chainId")).isEqualTo(expectedChainId.toString()); + } +} diff --git a/config/src/main/java/org/hyperledger/besu/config/GenesisConfigFile.java b/config/src/main/java/org/hyperledger/besu/config/GenesisConfigFile.java index 453c38dac20..8938e5143c2 100644 --- a/config/src/main/java/org/hyperledger/besu/config/GenesisConfigFile.java +++ b/config/src/main/java/org/hyperledger/besu/config/GenesisConfigFile.java @@ -280,6 +280,9 @@ public Optional getCoinbase() { * @return the timestamp */ public long getTimestamp() { + if (overrides != null && overrides.containsKey("timestamp")) { + return Long.parseLong(overrides.get("timestamp")); + } return parseLong("timestamp", JsonUtil.getValueAsString(genesisRoot, "timestamp", "0x0")); } diff --git a/config/src/main/resources/ephemery.json b/config/src/main/resources/ephemery.json new file mode 100644 index 00000000000..5c73756fb53 --- /dev/null +++ b/config/src/main/resources/ephemery.json @@ -0,0 +1,916 @@ +{ + "config": { + "chainId": 39438135, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "mergeNetsplitBlock": 0, + "terminalTotalDifficulty": 0, + "terminalTotalDifficultyPassed": true, + "shanghaiTime": 0, + "cancunTime": 0, + "depositContractAddress": "0x4242424242424242424242424242424242424242", + "ethash" : {}, + "discovery" : { + "bootnodes" : [ + "enode://50a54ecbd2175497640bcf46a25bbe9bb4fae51d7cc2a29ef4947a7ee17496cf39a699b7fe6b703ed0feb9dbaae7e44fc3827fcb7435ca9ac6de4daa4d983b3d@137.74.203.240:30303", + "enode://0f2c301a9a3f9fa2ccfa362b79552c052905d8c2982f707f46cd29ece5a9e1c14ecd06f4ac951b228f059a43c6284a1a14fce709e8976cac93b50345218bf2e9@135.181.140.168:30343" ] + } + }, + "alloc": { + "0x0000000000000000000000000000000000000000": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000001": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000002": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000003": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000004": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000005": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000006": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000007": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000008": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000009": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000010": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000011": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000012": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000013": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000014": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000015": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000016": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000017": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000018": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000019": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000020": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000021": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000022": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000023": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000024": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000025": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000026": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000027": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000028": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000029": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000030": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000031": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000032": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000033": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000034": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000035": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000036": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000037": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000038": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000039": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000040": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000041": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000042": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000043": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000044": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000045": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000046": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000047": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000048": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000049": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000050": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000051": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000052": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000053": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000054": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000055": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000056": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000057": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000058": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000059": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000060": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000061": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000062": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000063": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000064": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000065": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000066": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000067": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000068": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000069": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000070": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000071": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000072": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000073": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000074": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000075": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000076": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000077": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000078": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000079": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000080": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000081": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000082": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000083": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000084": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000085": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000086": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000087": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000088": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000089": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000090": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000091": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000092": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000093": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000094": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000095": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000096": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000097": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000098": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000099": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009f": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000aa": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ab": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ac": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ad": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ae": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000af": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ba": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000be": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bf": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ca": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ce": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cf": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000da": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000db": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000dc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000dd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000de": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000df": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ea": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000eb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ec": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ed": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ee": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ef": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fa": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fe": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ff": { + "balance": "1" + }, + "0x4242424242424242424242424242424242424242": { + "balance": "0", + "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a2646970667358221220dceca8706b29e917dacf25fceef95acac8d90d765ac926663ce4096195952b6164736f6c634300060b0033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000022": "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", + "0x0000000000000000000000000000000000000000000000000000000000000023": "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", + "0x0000000000000000000000000000000000000000000000000000000000000024": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", + "0x0000000000000000000000000000000000000000000000000000000000000025": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", + "0x0000000000000000000000000000000000000000000000000000000000000026": "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", + "0x0000000000000000000000000000000000000000000000000000000000000027": "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", + "0x0000000000000000000000000000000000000000000000000000000000000028": "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", + "0x0000000000000000000000000000000000000000000000000000000000000029": "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", + "0x000000000000000000000000000000000000000000000000000000000000002a": "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", + "0x000000000000000000000000000000000000000000000000000000000000002b": "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", + "0x000000000000000000000000000000000000000000000000000000000000002c": "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", + "0x000000000000000000000000000000000000000000000000000000000000002d": "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", + "0x000000000000000000000000000000000000000000000000000000000000002e": "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", + "0x000000000000000000000000000000000000000000000000000000000000002f": "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", + "0x0000000000000000000000000000000000000000000000000000000000000030": "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", + "0x0000000000000000000000000000000000000000000000000000000000000031": "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", + "0x0000000000000000000000000000000000000000000000000000000000000032": "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", + "0x0000000000000000000000000000000000000000000000000000000000000034": "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", + "0x0000000000000000000000000000000000000000000000000000000000000035": "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", + "0x0000000000000000000000000000000000000000000000000000000000000036": "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", + "0x0000000000000000000000000000000000000000000000000000000000000037": "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", + "0x0000000000000000000000000000000000000000000000000000000000000038": "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", + "0x0000000000000000000000000000000000000000000000000000000000000039": "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", + "0x000000000000000000000000000000000000000000000000000000000000003a": "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", + "0x000000000000000000000000000000000000000000000000000000000000003b": "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", + "0x000000000000000000000000000000000000000000000000000000000000003c": "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", + "0x000000000000000000000000000000000000000000000000000000000000003d": "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", + "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", + "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", + "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7" + } + }, + "0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02": { + "balance": "0", + "nonce": "1", + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500" + }, + "0xa2A6d93439144FFE4D27c9E088dCD8b783946263": { + "balance": "1000000000000000000000000" + }, + "0xBc11295936Aa79d594139de1B2e12629414F3BDB": { + "balance": "1000000000000000000000000" + }, + "0x7cF5b79bfe291A67AB02b393E456cCc4c266F753": { + "balance": "1000000000000000000000000" + }, + "0xaaec86394441f915bce3e6ab399977e9906f3b69": { + "balance": "1000000000000000000000000" + }, + "0xF47CaE1CF79ca6758Bfc787dbD21E6bdBe7112B8": { + "balance": "1000000000000000000000000" + }, + "0xd7eDDB78ED295B3C9629240E8924fb8D8874ddD8": { + "balance": "1000000000000000000000000" + }, + "0x8b7F0977Bb4f0fBE7076FA22bC24acA043583F5e": { + "balance": "1000000000000000000000000" + }, + "0xe2e2659028143784d557bcec6ff3a0721048880a": { + "balance": "1000000000000000000000000" + }, + "0xd9a5179f091d85051d3c982785efd1455cec8699": { + "balance": "1000000000000000000000000" + }, + "0xbeef32ca5b9a198d27B4e02F4c70439fE60356Cf": { + "balance": "1000000000000000000000000" + }, + "0x0000006916a87b82333f4245046623b23794c65c": { + "balance": "10000000000000000000000000" + }, + "0xb21c33de1fab3fa15499c62b59fe0cc3250020d1": { + "balance": "100000000000000000000000000" + }, + "0x10F5d45854e038071485AC9e402308cF80D2d2fE": { + "balance": "100000000000000000000000000" + }, + "0xd7d76c58b3a519e9fA6Cc4D22dC017259BC49F1E": { + "balance": "100000000000000000000000000" + }, + "0x799D329e5f583419167cD722962485926E338F4a": { + "balance": "1000000000000000000" + }, + "0x4c2ae482593505f0163cdefc073e81c63cda4107": { + "balance": "1000000000000000000000000" + }, + "0xa8e8f14732658e4b51e8711931053a8a69baf2b1": { + "balance": "1000000000000000000000000" + }, + "0xe0a2bd4258d2768837baa26a28fe71dc079f84c7": { + "balance": "100000000000000000000000000" + }, + "0x1eA692E68a7765dE26FC03A6D74EE5B56A7e2b4d": { + "balance": "100000000000000000000000000" + }, + "0x57c3dfd40A86628B67721115d7A03C9F341d7718": { + "balance": "100000000000000000000000000" + }, + "0xc90E920F4DCfd4954230edCaB168D0C5B9561e03": { + "balance": "1000000000000000000000000000" + }, + "0x6Cc9397c3B38739daCbfaA68EaD5F5D77Ba5F455": { + "balance": "10000000000000000000000000" + }, + "0x992775d32fd0ec76b95C5E76CeEA92ED5a4bE1F9": { + "balance": "10000000000000000000000000" + } + }, + "coinbase": "0x0000000000000000000000000000000000000000", + "difficulty": "0x01", + "extraData": "", + "gasLimit": "0x1c9c380", + "nonce": "0x1234", + "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "timestamp": "1720119600" +} From 5fd87d61f175eec7fd93c4c01bfaa530b5f3703e Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 4 Oct 2024 06:48:43 +0200 Subject: [PATCH 7/8] Support chainId in CallParameters (#7720) Signed-off-by: Fabio Di Fabio Co-authored-by: Sally MacFarlane --- CHANGELOG.md | 3 +- .../jsonrpc/JsonRpcTestMethodsFactory.java | 12 +++-- .../fork/london/EthCallIntegrationTest.java | 22 +++++++++ .../london/EthEstimateGasIntegrationTest.java | 30 ++++++++++++ .../internal/methods/AbstractEstimateGas.java | 5 +- .../parameters/JsonCallParameter.java | 19 ++++++++ .../core/json/ChainIdDeserializer.java | 46 +++++++++++++++++++ .../ethereum/transaction/CallParameter.java | 18 +++++++- .../transaction/TransactionSimulator.java | 11 +++-- .../transaction/TransactionSimulatorTest.java | 1 + 10 files changed, 157 insertions(+), 10 deletions(-) create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/json/ChainIdDeserializer.java diff --git a/CHANGELOG.md b/CHANGELOG.md index e304b72632f..379c87ee08c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,8 @@ - Add configuration of Consolidation Request Contract Address via genesis configuration [#7647](https://github.com/hyperledger/besu/pull/7647) - Interrupt pending transaction processing on block creation timeout [#7673](https://github.com/hyperledger/besu/pull/7673) - Align gas cap calculation for transaction simulation to Geth approach [#7703](https://github.com/hyperledger/besu/pull/7703) -- Expose chainId in the `BlockchainService` [7702](https://github.com/hyperledger/besu/pull/7702) +- Expose chainId in the `BlockchainService` [#7702](https://github.com/hyperledger/besu/pull/7702) +- Add support for `chainId` in `CallParameters` [#7720](https://github.com/hyperledger/besu/pull/7720) ### Bug fixes - Fix mounted data path directory permissions for besu user [#7575](https://github.com/hyperledger/besu/pull/7575) diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java index 538060a905b..c7ba5a4f934 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java @@ -68,7 +68,6 @@ public class JsonRpcTestMethodsFactory { private static final String CLIENT_NODE_NAME = "TestClientVersion/0.1.0"; private static final String CLIENT_VERSION = "0.1.0"; private static final String CLIENT_COMMIT = "12345678"; - private static final BigInteger NETWORK_ID = BigInteger.valueOf(123); private final BlockchainImporter importer; private final MutableBlockchain blockchain; @@ -76,6 +75,7 @@ public class JsonRpcTestMethodsFactory { private final ProtocolContext context; private final BlockchainQueries blockchainQueries; private final Synchronizer synchronizer; + private final ProtocolSchedule protocolSchedule; public JsonRpcTestMethodsFactory(final BlockchainImporter importer) { this.importer = importer; @@ -84,7 +84,7 @@ public JsonRpcTestMethodsFactory(final BlockchainImporter importer) { this.importer.getGenesisState().writeStateTo(stateArchive.getMutable()); this.context = new ProtocolContext(blockchain, stateArchive, null, new BadBlockManager()); - final ProtocolSchedule protocolSchedule = importer.getProtocolSchedule(); + this.protocolSchedule = importer.getProtocolSchedule(); this.synchronizer = mock(Synchronizer.class); for (final Block block : importer.getBlocks()) { @@ -106,6 +106,7 @@ public JsonRpcTestMethodsFactory( this.blockchain = blockchain; this.stateArchive = stateArchive; this.context = context; + this.protocolSchedule = importer.getProtocolSchedule(); this.blockchainQueries = new BlockchainQueries( importer.getProtocolSchedule(), @@ -126,6 +127,7 @@ public JsonRpcTestMethodsFactory( this.stateArchive = stateArchive; this.context = context; this.synchronizer = synchronizer; + this.protocolSchedule = importer.getProtocolSchedule(); this.blockchainQueries = new BlockchainQueries( importer.getProtocolSchedule(), @@ -142,6 +144,10 @@ public WorldStateArchive getStateArchive() { return stateArchive; } + public BigInteger getChainId() { + return protocolSchedule.getChainId().get(); + } + public Map methods() { final P2PNetwork peerDiscovery = mock(P2PNetwork.class); final EthPeers ethPeers = mock(EthPeers.class); @@ -183,7 +189,7 @@ public Map methods() { CLIENT_NODE_NAME, CLIENT_VERSION, CLIENT_COMMIT, - NETWORK_ID, + getChainId(), new StubGenesisConfigOptions(), peerDiscovery, blockchainQueries, diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthCallIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthCallIntegrationTest.java index 5f03d7f4d5f..9fb692ef82f 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthCallIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthCallIntegrationTest.java @@ -30,6 +30,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.testutil.BlockTestUtil; +import java.math.BigInteger; import java.util.Map; import com.google.common.base.Charsets; @@ -142,6 +143,7 @@ public void shouldReturnErrorWithGasPriceLessThanCurrentBaseFee() { public void shouldReturnSuccessWithValidMaxFeePerGas() { final JsonCallParameter callParameter = new JsonCallParameter.JsonCallParameterBuilder() + .withChainId(BLOCKCHAIN.getChainId()) .withFrom(Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")) .withTo(Address.fromHexString("0x9b8397f1b0fecd3a1a40cdd5e8221fa461898517")) .withMaxFeePerGas(Wei.fromHexString("0x3B9ACA01")) @@ -158,6 +160,26 @@ public void shouldReturnSuccessWithValidMaxFeePerGas() { assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse); } + @Test + public void shouldReturnErrorWithInvalidChainId() { + final JsonCallParameter callParameter = + new JsonCallParameter.JsonCallParameterBuilder() + .withChainId(BLOCKCHAIN.getChainId().add(BigInteger.ONE)) + .withFrom(Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")) + .withTo(Address.fromHexString("0x9b8397f1b0fecd3a1a40cdd5e8221fa461898517")) + .withMaxFeePerGas(Wei.fromHexString("0x3B9ACA01")) + .withInput(Bytes.fromHexString("0x2e64cec1")) + .build(); + + final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); + final JsonRpcResponse expectedResponse = + new JsonRpcErrorResponse(null, RpcErrorType.WRONG_CHAIN_ID); + + final JsonRpcResponse response = method.response(request); + + assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse); + } + @Test public void shouldReturnSuccessWithValidMaxFeePerGasAndMaxPriorityFeePerGas() { final JsonCallParameter callParameter = diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthEstimateGasIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthEstimateGasIntegrationTest.java index 84447dfc9d3..5fde9ccecbd 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthEstimateGasIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthEstimateGasIntegrationTest.java @@ -25,10 +25,15 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.mainnet.ValidationResult; +import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; import org.hyperledger.besu.testutil.BlockTestUtil; +import java.math.BigInteger; import java.util.List; import java.util.Map; @@ -112,6 +117,7 @@ public void shouldReturnExpectedValueForContractDeploy() { public void shouldReturnExpectedValueForContractDeploy_WithAccessList() { final JsonCallParameter callParameter = new JsonCallParameter.JsonCallParameterBuilder() + .withChainId(BLOCKCHAIN.getChainId()) .withFrom(Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")) .withInput( Bytes.fromHexString( @@ -124,6 +130,30 @@ public void shouldReturnExpectedValueForContractDeploy_WithAccessList() { assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse); } + @Test + public void shouldReturnErrorWithInvalidChainId() { + final JsonCallParameter callParameter = + new JsonCallParameter.JsonCallParameterBuilder() + .withChainId(BLOCKCHAIN.getChainId().add(BigInteger.ONE)) + .withFrom(Address.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")) + .withTo(Address.fromHexString("0x8888f1f195afa192cfee860698584c030f4c9db1")) + .withValue(Wei.ONE) + .build(); + + final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); + final JsonRpcResponse expectedResponse = + new JsonRpcErrorResponse( + null, + JsonRpcError.from( + ValidationResult.invalid( + TransactionInvalidReason.WRONG_CHAIN_ID, + "transaction was meant for chain id 1983 and not this chain id 1982"))); + + final JsonRpcResponse response = method.response(request); + + assertThat(response).usingRecursiveComparison().isEqualTo(expectedResponse); + } + private List createAccessList() { return List.of( new AccessListEntry( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractEstimateGas.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractEstimateGas.java index 4cbfb818dbe..8e826caf9e4 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractEstimateGas.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractEstimateGas.java @@ -103,6 +103,7 @@ protected abstract Object resultByBlockHeader( protected CallParameter overrideGasLimitAndPrice( final JsonCallParameter callParams, final long gasLimit) { return new CallParameter( + callParams.getChainId(), callParams.getFrom(), callParams.getTo(), gasLimit, @@ -111,7 +112,9 @@ protected CallParameter overrideGasLimitAndPrice( callParams.getMaxFeePerGas(), callParams.getValue(), callParams.getPayload(), - callParams.getAccessList()); + callParams.getAccessList(), + callParams.getMaxFeePerBlobGas(), + callParams.getBlobVersionedHashes()); } /** diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonCallParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonCallParameter.java index 987b68c2e2f..85dabda5719 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonCallParameter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonCallParameter.java @@ -18,10 +18,12 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.json.ChainIdDeserializer; import org.hyperledger.besu.ethereum.core.json.GasDeserializer; import org.hyperledger.besu.ethereum.core.json.HexStringDeserializer; import org.hyperledger.besu.ethereum.transaction.CallParameter; +import java.math.BigInteger; import java.util.List; import java.util.Optional; @@ -41,6 +43,7 @@ * *
{@code
  * JsonCallParameter param = new JsonCallParameter.JsonCallParameterBuilder()
+ *     .withChainId(Optional.of(BigInteger.ONE))
  *     .withFrom(Address.fromHexString("0x..."))
  *     .withTo(Address.fromHexString("0x..."))
  *     .withGas(21000L)
@@ -71,6 +74,7 @@ public class JsonCallParameter extends CallParameter {
   private final Optional strict;
 
   private JsonCallParameter(
+      final Optional chainId,
       final Address from,
       final Address to,
       final Long gasLimit,
@@ -85,6 +89,7 @@ private JsonCallParameter(
       final Optional> blobVersionedHashes) {
 
     super(
+        chainId,
         from,
         to,
         gasLimit,
@@ -115,6 +120,7 @@ public Optional isMaybeStrict() {
    */
   public static final class JsonCallParameterBuilder {
     private Optional strict = Optional.empty();
+    private Optional chainId = Optional.empty();
     private Address from;
     private Address to;
     private long gas = -1;
@@ -145,6 +151,18 @@ public JsonCallParameterBuilder withStrict(final Boolean strict) {
       return this;
     }
 
+    /**
+     * Sets the optional "chainId" for the {@link JsonCallParameter}.
+     *
+     * @param chainId the chainId
+     * @return the {@link JsonCallParameterBuilder} instance for chaining
+     */
+    @JsonDeserialize(using = ChainIdDeserializer.class)
+    public JsonCallParameterBuilder withChainId(final BigInteger chainId) {
+      this.chainId = Optional.of(chainId);
+      return this;
+    }
+
     /**
      * Sets the "from" address for the {@link JsonCallParameter}. This address represents the sender
      * of the call.
@@ -346,6 +364,7 @@ public JsonCallParameter build() {
       final Bytes payload = input != null ? input : data;
 
       return new JsonCallParameter(
+          chainId,
           from,
           to,
           gas,
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/json/ChainIdDeserializer.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/json/ChainIdDeserializer.java
new file mode 100644
index 00000000000..04be922ecd2
--- /dev/null
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/json/ChainIdDeserializer.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright contributors to Hyperledger Besu.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package org.hyperledger.besu.ethereum.core.json;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import org.apache.tuweni.units.bigints.UInt256;
+
+public class ChainIdDeserializer extends StdDeserializer {
+
+  public ChainIdDeserializer() {
+    this(null);
+  }
+
+  public ChainIdDeserializer(final Class vc) {
+    super(vc);
+  }
+
+  @Override
+  public BigInteger deserialize(final JsonParser jsonparser, final DeserializationContext context)
+      throws IOException {
+    final var chainId =
+        UInt256.fromHexString(jsonparser.getCodec().readValue(jsonparser, String.class))
+            .toBigInteger();
+    if (chainId.signum() <= 0) {
+      throw new IllegalArgumentException("Non positive chain id: " + chainId);
+    }
+    return chainId;
+  }
+}
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/CallParameter.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/CallParameter.java
index 292c65cac61..ce2e63a71a0 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/CallParameter.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/CallParameter.java
@@ -20,6 +20,7 @@
 import org.hyperledger.besu.datatypes.Wei;
 import org.hyperledger.besu.ethereum.core.Transaction;
 
+import java.math.BigInteger;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
@@ -28,6 +29,7 @@
 
 // Represents parameters for eth_call and eth_estimateGas JSON-RPC methods.
 public class CallParameter {
+  private final Optional chainId;
 
   private final Address from;
 
@@ -56,6 +58,7 @@ public CallParameter(
       final Wei gasPrice,
       final Wei value,
       final Bytes payload) {
+    this.chainId = Optional.empty();
     this.from = from;
     this.to = to;
     this.gasLimit = gasLimit;
@@ -79,6 +82,7 @@ public CallParameter(
       final Wei value,
       final Bytes payload,
       final Optional> accessList) {
+    this.chainId = Optional.empty();
     this.from = from;
     this.to = to;
     this.gasLimit = gasLimit;
@@ -93,6 +97,7 @@ public CallParameter(
   }
 
   public CallParameter(
+      final Optional chainId,
       final Address from,
       final Address to,
       final long gasLimit,
@@ -104,6 +109,7 @@ public CallParameter(
       final Optional> accessList,
       final Optional maxFeePerBlobGas,
       final Optional> blobVersionedHashes) {
+    this.chainId = chainId;
     this.from = from;
     this.to = to;
     this.gasLimit = gasLimit;
@@ -117,6 +123,10 @@ public CallParameter(
     this.blobVersionedHashes = blobVersionedHashes;
   }
 
+  public Optional getChainId() {
+    return chainId;
+  }
+
   public Address getFrom() {
     return from;
   }
@@ -171,6 +181,7 @@ public boolean equals(final Object o) {
     }
     final CallParameter that = (CallParameter) o;
     return gasLimit == that.gasLimit
+        && chainId.equals(that.chainId)
         && Objects.equals(from, that.from)
         && Objects.equals(to, that.to)
         && Objects.equals(gasPrice, that.gasPrice)
@@ -186,6 +197,7 @@ public boolean equals(final Object o) {
   @Override
   public int hashCode() {
     return Objects.hash(
+        chainId,
         from,
         to,
         gasLimit,
@@ -202,7 +214,9 @@ public int hashCode() {
   @Override
   public String toString() {
     return "CallParameter{"
-        + "from="
+        + "chainId="
+        + chainId
+        + ", from="
         + from
         + ", to="
         + to
@@ -229,6 +243,7 @@ public String toString() {
 
   public static CallParameter fromTransaction(final Transaction tx) {
     return new CallParameter(
+        tx.getChainId(),
         tx.getSender(),
         tx.getTo().orElse(null),
         tx.getGasLimit(),
@@ -244,6 +259,7 @@ public static CallParameter fromTransaction(final Transaction tx) {
 
   public static CallParameter fromTransaction(final org.hyperledger.besu.datatypes.Transaction tx) {
     return new CallParameter(
+        tx.getChainId(),
         tx.getSender(),
         tx.getTo().orElse(null),
         tx.getGasLimit(),
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java
index 5e78256a789..321dc965ecd 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java
@@ -369,10 +369,13 @@ private Optional buildTransaction(
       transactionBuilder.maxFeePerBlobGas(maxFeePerBlobGas);
     }
     if (transactionBuilder.getTransactionType().requiresChainId()) {
-      transactionBuilder.chainId(
-          protocolSchedule
-              .getChainId()
-              .orElse(BigInteger.ONE)); // needed to make some transactions valid
+      callParams
+          .getChainId()
+          .ifPresentOrElse(
+              transactionBuilder::chainId,
+              () ->
+                  // needed to make some transactions valid
+                  transactionBuilder.chainId(protocolSchedule.getChainId().orElse(BigInteger.ONE)));
     }
 
     final Transaction transaction = transactionBuilder.build();
diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java
index 73fa402abbd..c6c676c4151 100644
--- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java
+++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java
@@ -858,6 +858,7 @@ private CallParameter blobTransactionCallParameter(
       final int numberOfBlobs) {
     BlobsWithCommitments bwc = new BlobTestFixture().createBlobsWithCommitments(numberOfBlobs);
     return new CallParameter(
+        Optional.of(BigInteger.ONE),
         Address.fromHexString("0x0"),
         Address.fromHexString("0x0"),
         gasLimit,

From 81f9fc9c332a51380c6678df790b7e374751ef0d Mon Sep 17 00:00:00 2001
From: Danno Ferrin 
Date: Thu, 3 Oct 2024 23:25:29 -0600
Subject: [PATCH 8/8] Change evmtool eof-test handling of empty code (#7675)

In EOFTest, treat empty code as invalid.

Signed-off-by: Danno Ferrin 
---
 .../java/org/hyperledger/besu/evmtool/EOFTestSubCommand.java    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EOFTestSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EOFTestSubCommand.java
index 94f8b2cd492..fb28701f777 100644
--- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EOFTestSubCommand.java
+++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EOFTestSubCommand.java
@@ -224,7 +224,7 @@ public TestResult considerCode(final String hexCode) {
       return failed(re.getMessage());
     }
     if (codeBytes.isEmpty()) {
-      return passed();
+      return failed("invalid_magic code is zero-length");
     }
 
     var layout = EOFLayout.parseEOF(codeBytes);