Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b521f25
Simplify bootnode parsing and add v5Bootnodes to genesis configs
usmansaleem Mar 5, 2026
ad8b277
Remove stale prefix detection and fix v5Bootnodes key normalization
usmansaleem Mar 5, 2026
8c37051
Merge remote-tracking branch 'upstream/main' into fix/9968-enr-bootnodes
usmansaleem Mar 5, 2026
a26f9cf
Clear unused bootnode list based on discovery protocol version
usmansaleem Mar 5, 2026
e484e48
fix unit test
usmansaleem Mar 5, 2026
63734c6
Clear unused bootnode list only on CLI override, use V5 flag in getBo…
usmansaleem Mar 5, 2026
8e09351
review suggestion
usmansaleem Mar 5, 2026
a89f3d0
Fix BesuCommandTest to use EthNetworkConfig for mainnet defaults
usmansaleem Mar 5, 2026
6756407
Fix CascadingDefaultProviderTest for mainnet ENR bootnodes
usmansaleem Mar 5, 2026
e771463
Fix ENR public key decompression to always use secp256k1
usmansaleem Mar 5, 2026
d159fb9
Merge remote-tracking branch 'upstream/main' into fix/9968-enr-bootnodes
usmansaleem Mar 5, 2026
5614f90
Merge remote-tracking branch 'upstream/main' into fix/9968-enr-bootnodes
usmansaleem Mar 5, 2026
7447039
Improve error handling for invalid ENR bootnodes and add V5 bootnode …
usmansaleem Mar 6, 2026
6000bbe
Improve error message for invalid ENR bootnodes
usmansaleem Mar 8, 2026
74c7048
Merge remote-tracking branch 'upstream/main' into fix/9968-enr-bootnodes
usmansaleem Mar 8, 2026
4d13fe6
Merge remote-tracking branch 'upstream/main' into fix/9968-enr-bootnodes
usmansaleem Mar 9, 2026
d72eeb8
Merge remote-tracking branch 'upstream/main' into fix/9968-enr-bootnodes
usmansaleem Mar 10, 2026
f53a376
Fix DiscV5 ECDH key agreement and peer connection pipeline
usmansaleem Mar 10, 2026
67f64cc
Apply spotless formatting
usmansaleem Mar 10, 2026
c2866d5
Merge remote-tracking branch 'upstream/main' into fix/9968-enr-bootnodes
usmansaleem Mar 11, 2026
3b3707e
Explicitly use secp256k1 for ENR identity scheme v4
usmansaleem Mar 11, 2026
932360d
Merge remote-tracking branch 'upstream/main' into fix/9968-enr-bootnodes
usmansaleem Mar 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 6 additions & 13 deletions app/src/main/java/org/hyperledger/besu/RunnerBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.cli.options.EthstatsOptions;
import org.hyperledger.besu.config.NetworkDefinition;
import org.hyperledger.besu.controller.BesuController;
import org.hyperledger.besu.cryptoservices.NodeKey;
import org.hyperledger.besu.ethereum.ProtocolContext;
Expand Down Expand Up @@ -672,25 +671,19 @@ public Runner build() {
});
discoveryConfiguration.setPreferIpv6Outbound(preferIpv6Outbound);
if (discoveryEnabled) {
final List<EnodeURLImpl> bootstrap;
if (ethNetworkConfig.enodeBootNodes() == null) {
bootstrap = EthNetworkConfig.getNetworkConfig(NetworkDefinition.MAINNET).enodeBootNodes();
} else {
bootstrap = ethNetworkConfig.enodeBootNodes();
}
discoveryConfiguration.setEnodeBootnodes(bootstrap);
discoveryConfiguration.setEnrBootnodes(
ethNetworkConfig.enrBootNodes() == null
? EthNetworkConfig.getNetworkConfig(NetworkDefinition.MAINNET).enrBootNodes()
: ethNetworkConfig.enrBootNodes());
discoveryConfiguration.setEnodeBootnodes(ethNetworkConfig.enodeBootNodes());
discoveryConfiguration.setEnrBootnodes(ethNetworkConfig.enrBootNodes());

discoveryConfiguration.setIncludeBootnodesOnPeerRefresh(
besuController.getGenesisConfigOptions().isPoa() && poaDiscoveryRetryBootnodes);
LOG.info(
"Resolved {} bootnodes.",
discoveryConfiguration.getEnodeBootnodes().size()
+ discoveryConfiguration.getEnrBootnodes().size());
LOG.debug("Bootnodes = {}", bootstrap);
LOG.debug(
"Bootnodes enode={}, enr={}",
discoveryConfiguration.getEnodeBootnodes(),
discoveryConfiguration.getEnrBootnodes());
discoveryConfiguration.setDnsDiscoveryURL(ethNetworkConfig.dnsDiscoveryUrl());
discoveryConfiguration.setDiscoveryV5Enabled(
networkingConfiguration.discoveryConfiguration().isDiscoveryV5Enabled());
Expand Down
95 changes: 63 additions & 32 deletions app/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
import org.hyperledger.besu.cli.util.VersionProvider;
import org.hyperledger.besu.components.BesuComponent;
import org.hyperledger.besu.config.CheckpointConfigOptions;
import org.hyperledger.besu.config.DiscoveryOptions;
import org.hyperledger.besu.config.GenesisConfig;
import org.hyperledger.besu.config.GenesisConfigOptions;
import org.hyperledger.besu.config.JsonUtil;
Expand Down Expand Up @@ -2517,6 +2518,7 @@ private EthNetworkConfig updateNetworkConfig(final NetworkDefinition network) {

if (p2PDiscoveryOptions.bootNodes == null) {
builder.setEnodeBootNodes(new ArrayList<>());
builder.setEnrBootNodes(new ArrayList<>());
}
builder.setDnsDiscoveryUrl(null);
}
Expand All @@ -2539,46 +2541,75 @@ private EthNetworkConfig updateNetworkConfig(final NetworkDefinition network) {
discoveryDnsUrlFromGenesis.ifPresent(builder::setDnsDiscoveryUrl);
}

List<EnodeURLImpl> listBootNodes = null;
if (p2PDiscoveryOptions.bootNodes != null) {
// Resolve bootnodes: CLI --bootnodes overrides genesis defaults.
// The discovery protocol version determines the expected format:
// V5 → ENR strings ("enr:..."), V4 → enode URLs ("enode://...")
final boolean isV5 =
unstableNetworkingOptions.toDomainObject().discoveryConfiguration().isDiscoveryV5Enabled();
List<String> rawBootnodes = null;
Comment thread
usmansaleem marked this conversation as resolved.
final boolean cliBootnodesProvided = p2PDiscoveryOptions.bootNodes != null;
if (cliBootnodesProvided) {
try {
final List<String> resolvedBootNodeArgs =
BootnodeResolver.resolve(p2PDiscoveryOptions.bootNodes);
if (!resolvedBootNodeArgs.isEmpty()) {
if (resolvedBootNodeArgs.getFirst().startsWith("enr:")) {
builder.setEnrBootNodes(
resolvedBootNodeArgs.stream().map(EthereumNodeRecord::fromEnr).toList());
} else {
listBootNodes = buildEnodes(resolvedBootNodeArgs, getEnodeDnsConfiguration());
}
} else {
listBootNodes = Collections.emptyList();
}

} catch (final BootnodeResolutionException e) {
rawBootnodes = BootnodeResolver.resolve(p2PDiscoveryOptions.bootNodes);
} catch (final BootnodeResolutionException | IllegalArgumentException e) {
throw new ParameterException(commandLine, e.getMessage(), e);

} catch (final IllegalArgumentException e) {
throw new ParameterException(commandLine, e.getMessage());
}
} else {
final Optional<List<String>> bootNodesFromGenesis =
genesisConfigOptionsSupplier.get().getDiscoveryOptions().getBootNodes();
if (bootNodesFromGenesis.isPresent() && !bootNodesFromGenesis.get().isEmpty()) {
if (bootNodesFromGenesis.get().getFirst().startsWith("enr:")) {
builder.setEnrBootNodes(
bootNodesFromGenesis.get().stream().map(EthereumNodeRecord::fromEnr).toList());
} else {
listBootNodes = buildEnodes(bootNodesFromGenesis.get(), getEnodeDnsConfiguration());
}
}
final DiscoveryOptions discoveryOptions =
genesisConfigOptionsSupplier.get().getDiscoveryOptions();
rawBootnodes =
isV5
? discoveryOptions.getV5BootNodes().orElse(null)
: discoveryOptions.getBootNodes().orElse(null);
}
if (listBootNodes != null) {

if (rawBootnodes != null && !rawBootnodes.isEmpty()) {
if (!p2PDiscoveryOptions.peerDiscoveryEnabled) {
logger.warn("Discovery disabled: bootnodes will be ignored.");
}
DiscoveryConfiguration.assertValidBootnodes(listBootNodes);
builder.setEnodeBootNodes(listBootNodes);
try {
if (isV5) {
builder.setEnrBootNodes(
rawBootnodes.stream()
.map(
enr -> {
try {
return EthereumNodeRecord.fromEnr(enr);
} catch (final Exception e) {
throw new ParameterException(
commandLine,
"Invalid ENR bootnode: '"
+ enr
+ "'. ENR bootnodes must start with 'enr:'. Error: "
+ e.getMessage(),
e);
}
})
.toList());
} else {
final List<EnodeURLImpl> enodes = buildEnodes(rawBootnodes, getEnodeDnsConfiguration());
DiscoveryConfiguration.assertValidBootnodes(enodes);
Comment thread
usmansaleem marked this conversation as resolved.
builder.setEnodeBootNodes(enodes);
}
// CLI --bootnodes is a full override: clear the unused protocol's list
if (cliBootnodesProvided) {
if (isV5) {
builder.setEnodeBootNodes(Collections.emptyList());
} else {
builder.setEnrBootNodes(Collections.emptyList());
}
}
} catch (final ParameterException e) {
throw e; // re-throw ParameterException from ENR parsing as-is
} catch (final IllegalArgumentException e) {
throw new ParameterException(commandLine, e.getMessage());
Comment thread
usmansaleem marked this conversation as resolved.
} catch (final RuntimeException e) {
throw new ParameterException(commandLine, "Invalid bootnode format: " + e.getMessage(), e);
}
} else if (cliBootnodesProvided) {
// Explicitly empty --bootnodes clears all default bootnodes
builder.setEnodeBootNodes(Collections.emptyList());
builder.setEnrBootNodes(Collections.emptyList());
}
return builder.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
*/
package org.hyperledger.besu.cli.config;

import org.hyperledger.besu.config.DiscoveryOptions;
import org.hyperledger.besu.config.GenesisConfig;
import org.hyperledger.besu.config.GenesisConfigOptions;
import org.hyperledger.besu.config.NetworkDefinition;
import org.hyperledger.besu.ethereum.p2p.discovery.dns.EthereumNodeRecord;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
Expand All @@ -25,10 +25,8 @@
import java.math.BigInteger;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
* The Eth network config.
Expand Down Expand Up @@ -72,25 +70,27 @@ public record EthNetworkConfig(
public static EthNetworkConfig getNetworkConfig(final NetworkDefinition networkDefinition) {
final URL genesisSource = jsonConfigSource(networkDefinition.getGenesisFile());
final GenesisConfig genesisConfig = GenesisConfig.fromSource(genesisSource);
final GenesisConfigOptions genesisConfigOptions = genesisConfig.getConfigOptions();
final Optional<List<String>> rawBootNodes =
genesisConfigOptions.getDiscoveryOptions().getBootNodes();
final List<EnodeURLImpl> enodeBootNodes = new ArrayList<>();
final List<EthereumNodeRecord> enrBootNodes = new ArrayList<>();
if (rawBootNodes.isPresent() && !rawBootNodes.get().isEmpty()) {
if (rawBootNodes.get().getFirst().startsWith("enr:")) {
enrBootNodes.addAll(rawBootNodes.get().stream().map(EthereumNodeRecord::fromEnr).toList());
} else {
enodeBootNodes.addAll(rawBootNodes.get().stream().map(EnodeURLImpl::fromString).toList());
}
}
final DiscoveryOptions discoveryOptions =
genesisConfig.getConfigOptions().getDiscoveryOptions();

final List<EnodeURLImpl> enodeBootNodes =
discoveryOptions
.getBootNodes()
.map(nodes -> nodes.stream().map(EnodeURLImpl::fromString).toList())
.orElse(List.of());

final List<EthereumNodeRecord> enrBootNodes =
discoveryOptions
.getV5BootNodes()
.map(nodes -> nodes.stream().map(EthereumNodeRecord::fromEnr).toList())
.orElse(List.of());

return new EthNetworkConfig(
genesisConfig,
networkDefinition.getNetworkId(),
enodeBootNodes,
enrBootNodes,
genesisConfigOptions.getDiscoveryOptions().getDiscoveryDnsUrl().orElse(null));
discoveryOptions.getDiscoveryDnsUrl().orElse(null));
}

private static URL jsonConfigSource(final String resourceName) {
Expand Down
52 changes: 44 additions & 8 deletions app/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.ArgumentCaptor;
import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension;
Expand Down Expand Up @@ -306,14 +308,7 @@ public void callingBesuCommandWithoutOptionsMustSyncWithDefaultValues() {
final ArgumentCaptor<EthNetworkConfig> ethNetworkArg =
ArgumentCaptor.forClass(EthNetworkConfig.class);
verify(mockRunnerBuilder).discoveryEnabled(eq(true));
verify(mockRunnerBuilder)
.ethNetworkConfig(
new EthNetworkConfig(
GenesisConfig.fromResource(MAINNET.getGenesisFile()),
MAINNET.getNetworkId(),
MAINNET_BOOTSTRAP_NODES,
Collections.emptyList(),
MAINNET_DISCOVERY_URL));
verify(mockRunnerBuilder).ethNetworkConfig(EthNetworkConfig.getNetworkConfig(MAINNET));
verify(mockRunnerBuilder).p2pAdvertisedHost(eq("127.0.0.1"));
verify(mockRunnerBuilder).p2pListenPort(eq(30303));
verify(mockRunnerBuilder).jsonRpcConfiguration(eq(DEFAULT_JSON_RPC_CONFIGURATION));
Expand Down Expand Up @@ -958,6 +953,7 @@ public void callingWithBootnodesOptionButNoValueMustPassEmptyBootnodeList() {
verify(mockRunnerBuilder).build();

assertThat(ethNetworkConfigArgumentCaptor.getValue().enodeBootNodes()).isEmpty();
assertThat(ethNetworkConfigArgumentCaptor.getValue().enrBootNodes()).isEmpty();

assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
Expand Down Expand Up @@ -1020,6 +1016,46 @@ public void callingWithInvalidBootnodeAndEqualSignMustDisplayError() {
assertThat(commandErrorOutput.toString(UTF_8)).startsWith(expectedErrorOutputStart);
}

private static final String VALID_ENR_1 =
"enr:-Iu4QLm7bZGdAt9NSeJG0cEnJohWcQTQaI9wFLu3Q7eHIDfrI4cwtzvEW3F3VbG9XdFXlrHyFGeXPn9snTCQJ9bnMRABgmlkgnY0gmlwhAOTJQCJc2VjcDI1NmsxoQIZdZD6tDYpkpEfVo5bgiU8MGRjhcOmHGD2nErK0UKRrIN0Y3CCIyiDdWRwgiMo";
private static final String VALID_ENR_2 =
"enr:-Iu4QEDJ4Wa_UQNbK8Ay1hFEkXvd8psolVK6OhfTL9irqz3nbXxxWyKwEplPfkju4zduVQj6mMhUCm9R2Lc4YM5jPcIBgmlkgnY0gmlwhANrfESJc2VjcDI1NmsxoQJCYz2-nsqFpeEj6eov9HSi9QssIVIVNr0I89J1vXM9foN0Y3CCIyiDdWRwgiMo";

@Test
public void callingWithValidEnrBootnodeAndV5EnabledMustSucceed() {
parseCommand("--Xv5-discovery-enabled", "--bootnodes", VALID_ENR_1);

verify(mockRunnerBuilder).ethNetworkConfig(ethNetworkConfigArgumentCaptor.capture());
verify(mockRunnerBuilder).build();

assertThat(ethNetworkConfigArgumentCaptor.getValue().enrBootNodes()).hasSize(1);
assertThat(ethNetworkConfigArgumentCaptor.getValue().enodeBootNodes()).isEmpty();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}

@Test
public void callingWithMultipleValidEnrBootnodesAndV5EnabledMustSucceed() {
parseCommand("--Xv5-discovery-enabled", "--bootnodes", VALID_ENR_1 + "," + VALID_ENR_2);

verify(mockRunnerBuilder).ethNetworkConfig(ethNetworkConfigArgumentCaptor.capture());
verify(mockRunnerBuilder).build();

assertThat(ethNetworkConfigArgumentCaptor.getValue().enrBootNodes()).hasSize(2);
assertThat(ethNetworkConfigArgumentCaptor.getValue().enodeBootNodes()).isEmpty();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}

@ParameterizedTest
@ValueSource(strings = {"enr:-invalidenrdata", "enr:invalidvalue", "invalidvalue"})
public void callingWithInvalidBootnodeAndV5EnabledMustDisplayError(final String bootnode) {
parseCommand("--Xv5-discovery-enabled", "--bootnodes", bootnode);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8))
.contains("Invalid ENR bootnode: '" + bootnode + "'");
}

@Test
public void bootnodesOptionMustBeUsed() {
parseCommand("--bootnodes", String.join(",", VALID_ENODE_STRINGS));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
import static org.hyperledger.besu.config.NetworkDefinition.MAINNET;
import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis.ETH;
import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis.WEB3;
import static org.hyperledger.besu.ethereum.p2p.config.DefaultDiscoveryConfiguration.MAINNET_BOOTSTRAP_NODES;
import static org.hyperledger.besu.ethereum.p2p.config.DefaultDiscoveryConfiguration.MAINNET_DISCOVERY_URL;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
Expand Down Expand Up @@ -132,6 +130,7 @@ public void overrideDefaultValuesIfKeyIsPresentInConfigFile(final @TempDir File
.setNetworkId(BigInteger.valueOf(42))
.setGenesisConfig(GenesisConfig.fromConfig(encodeJsonGenesis(GENESIS_VALID_JSON)))
.setEnodeBootNodes(nodes)
.setEnrBootNodes(Collections.emptyList())
.setDnsDiscoveryUrl(null)
.build();
verify(mockControllerBuilder).dataDirectory(eq(dataFolder.toPath()));
Expand Down Expand Up @@ -165,14 +164,7 @@ public void noOverrideDefaultValuesIfKeyIsNotPresentInConfigFile() {
final MetricsConfiguration metricsConfiguration = MetricsConfiguration.builder().build();

verify(mockRunnerBuilder).discoveryEnabled(eq(true));
verify(mockRunnerBuilder)
.ethNetworkConfig(
new EthNetworkConfig(
GenesisConfig.fromResource(MAINNET.getGenesisFile()),
MAINNET.getNetworkId(),
MAINNET_BOOTSTRAP_NODES,
Collections.emptyList(),
MAINNET_DISCOVERY_URL));
verify(mockRunnerBuilder).ethNetworkConfig(EthNetworkConfig.getNetworkConfig(MAINNET));
verify(mockRunnerBuilder).p2pAdvertisedHost(eq("127.0.0.1"));
verify(mockRunnerBuilder).p2pListenPort(eq(30303));
verify(mockRunnerBuilder).jsonRpcConfiguration(eq(jsonRpcConfiguration));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public void testDefaultMainnetConfig() {
EthNetworkConfig config = EthNetworkConfig.getNetworkConfig(NetworkDefinition.MAINNET);
assertThat(config.dnsDiscoveryUrl()).isEqualTo(MAINNET_DISCOVERY_URL);
assertThat(config.enodeBootNodes()).isEqualTo(MAINNET_BOOTSTRAP_NODES);
assertThat(config.enrBootNodes()).isNotEmpty();
assertThat(config.networkId()).isEqualTo(BigInteger.ONE);
Comment thread
usmansaleem marked this conversation as resolved.
}

Expand All @@ -56,6 +57,7 @@ public void testDefaultHoodiConfig() {
EthNetworkConfig config = EthNetworkConfig.getNetworkConfig(NetworkDefinition.HOODI);
assertThat(config.dnsDiscoveryUrl()).isEqualTo(HOODI_DISCOVERY_URL);
assertThat(config.enodeBootNodes()).isEqualTo(HOODI_BOOTSTRAP_NODES);
assertThat(config.enrBootNodes()).isNotEmpty();
assertThat(config.networkId()).isEqualTo(BigInteger.valueOf(560048));
Comment thread
usmansaleem marked this conversation as resolved.
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class DiscoveryOptions {
new DiscoveryOptions(JsonUtil.createEmptyObjectNode());

private static final String ENODES_KEY = "bootnodes";
private static final String V5_BOOTNODES_KEY = "v5bootnodes";
Comment thread
usmansaleem marked this conversation as resolved.
private static final String DNS_KEY = "dns";
Comment thread
usmansaleem marked this conversation as resolved.

private final ObjectNode discoveryConfigRoot;
Expand Down Expand Up @@ -67,6 +68,32 @@ public Optional<List<String>> getBootNodes() {
return Optional.of(bootNodes);
}

/**
* Gets V5 boot nodes (ENR format).
*
* @return optional list of ENR boot node strings
*/
public Optional<List<String>> getV5BootNodes() {
final Optional<ArrayNode> bootNodesArray =
JsonUtil.getArrayNode(discoveryConfigRoot, V5_BOOTNODES_KEY);
Comment thread
usmansaleem marked this conversation as resolved.
if (bootNodesArray.isEmpty()) {
return Optional.empty();
}
final List<String> bootNodes = new ArrayList<>();
bootNodesArray
.get()
.elements()
.forEachRemaining(
bootNodeElement -> {
if (!bootNodeElement.isTextual()) {
throw new IllegalArgumentException(
V5_BOOTNODES_KEY + " does not contain a string: " + bootNodeElement);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

think it would be more helpful to say "must contain strings of the form enr:-xyz"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I followed how bootnodes were parsed from the genesis configuration file in getBootNodes in the same file.

}
bootNodes.add(bootNodeElement.asText());
});
return Optional.of(bootNodes);
}

/**
* Gets discovery dns url.
*
Expand Down
Loading