use fork id to filter out non matching peers (#4459)

* use fork id to filter out non matching peers

Signed-off-by: Stefan <stefan.pingel@consensys.net>
pull/4694/head
Stefan Pingel 2 years ago committed by GitHub
parent 7c35be3936
commit e02cc04e41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java
  2. 33
      besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java
  3. 32
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  4. 9
      besu/src/main/java/org/hyperledger/besu/cli/options/unstable/NetworkingOptions.java
  5. 320
      besu/src/test/java/org/hyperledger/besu/ForkIdsTest.java
  6. 54
      besu/src/test/java/org/hyperledger/besu/RunnerBuilderTest.java
  7. 4
      besu/src/test/java/org/hyperledger/besu/RunnerTest.java
  8. 6
      besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java
  9. 36
      besu/src/test/java/org/hyperledger/besu/cli/options/NetworkingOptionsTest.java
  10. 14
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java
  11. 20
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/forkid/ForkId.java
  12. 6
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/forkid/ForkIdManager.java
  13. 17
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeers.java
  14. 2
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java
  15. 2
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/messages/StatusMessage.java
  16. 2
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/peervalidation/PeerValidatorRunner.java
  17. 2
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/PivotSelectorFromPeers.java
  18. 4
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/ForkIdBackwardCompatibilityTest.java
  19. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/ForkIdTestUtil.java
  20. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/LegacyForkIdManager.java
  21. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EIP2124Test.java
  22. 1
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java
  23. 1
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTestUtil.java
  24. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/StatusMessageTest.java
  25. 3
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java
  26. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java
  27. 17
      ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/config/DiscoveryConfiguration.java
  28. 7
      ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/DiscoveryPeer.java
  29. 17
      ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryAgent.java
  30. 5
      ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryStatus.java
  31. 7
      ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/VertxPeerDiscoveryAgent.java
  32. 183
      ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryController.java
  33. 39
      ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java
  34. 8
      ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryAgentTest.java
  35. 9
      ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryTestHelper.java
  36. 19
      ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/MockPeerDiscoveryAgent.java
  37. 194
      ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryControllerTest.java
  38. 2
      ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryTableRefreshTest.java
  39. 35
      ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetworkTest.java
  40. 43
      ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/NetworkingServiceLifecycleTest.java
  41. 10
      ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/P2PNetworkTest.java
  42. 18
      ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/P2PPlainNetworkTest.java

@ -220,7 +220,6 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
.besuPluginContext(new BesuPluginContextImpl())
.autoLogBloomCaching(false)
.storageProvider(storageProvider)
.forkIdSupplier(() -> besuController.getProtocolManager().getForkIdAsBytesList())
.rpcEndpointService(new RpcEndpointServiceImpl());
node.engineRpcConfiguration().ifPresent(runnerBuilder::engineJsonRpcConfiguration);

@ -133,7 +133,6 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -191,9 +190,9 @@ public class RunnerBuilder {
private boolean autoLogBloomCaching = true;
private boolean randomPeerPriority;
private StorageProvider storageProvider;
private Supplier<List<Bytes>> forkIdSupplier;
private RpcEndpointServiceImpl rpcEndpointServiceImpl;
private JsonRpcIpcConfiguration jsonRpcIpcConfiguration;
private boolean legacyForkIdEnabled;
public RunnerBuilder vertx(final Vertx vertx) {
this.vertx = vertx;
@ -388,11 +387,6 @@ public class RunnerBuilder {
return this;
}
public RunnerBuilder forkIdSupplier(final Supplier<List<Bytes>> forkIdSupplier) {
this.forkIdSupplier = forkIdSupplier;
return this;
}
public RunnerBuilder rpcEndpointService(final RpcEndpointServiceImpl rpcEndpointService) {
this.rpcEndpointServiceImpl = rpcEndpointService;
return this;
@ -424,6 +418,8 @@ public class RunnerBuilder {
discoveryConfiguration.setDnsDiscoveryURL(ethNetworkConfig.getDnsDiscoveryUrl());
discoveryConfiguration.setDiscoveryV5Enabled(
networkingConfiguration.getDiscovery().isDiscoveryV5Enabled());
discoveryConfiguration.setFilterOnEnrForkId(
networkingConfiguration.getDiscovery().isFilterOnEnrForkIdEnabled());
} else {
discoveryConfiguration.setActive(false);
}
@ -487,14 +483,16 @@ public class RunnerBuilder {
.vertx(vertx)
.nodeKey(nodeKey)
.config(networkingConfiguration)
.legacyForkIdEnabled(legacyForkIdEnabled)
.peerPermissions(peerPermissions)
.metricsSystem(metricsSystem)
.supportedCapabilities(caps)
.natService(natService)
.randomPeerPriority(randomPeerPriority)
.storageProvider(storageProvider)
.forkIdSupplier(forkIdSupplier)
.p2pTLSConfiguration(p2pTLSConfiguration)
.blockchain(context.getBlockchain())
.forks(besuController.getGenesisConfigOptions().getForks())
.build();
final NetworkRunner networkRunner =
@ -663,7 +661,7 @@ public class RunnerBuilder {
dataDir,
rpcEndpointServiceImpl);
Optional<AuthenticationService> authToUse =
final Optional<AuthenticationService> authToUse =
engineJsonRpcConfiguration.get().isAuthenticationEnabled()
? Optional.of(
new EngineAuthService(
@ -673,7 +671,7 @@ public class RunnerBuilder {
dataDir))
: Optional.empty();
WebSocketConfiguration engineSocketConfig =
final WebSocketConfiguration engineSocketConfig =
webSocketConfiguration.isEnabled()
? webSocketConfiguration
: WebSocketConfiguration.createEngineDefault();
@ -784,7 +782,8 @@ public class RunnerBuilder {
createPrivateTransactionObserver(subscriptionManager, privacyParameters);
}
Optional<MetricsService> metricsService = createMetricsService(vertx, metricsConfiguration);
final Optional<MetricsService> metricsService =
createMetricsService(vertx, metricsConfiguration);
final Optional<EthStatsService> ethStatsService;
if (!Strings.isNullOrEmpty(ethstatsUrl)) {
@ -807,7 +806,7 @@ public class RunnerBuilder {
final Optional<JsonRpcIpcService> jsonRpcIpcService;
if (jsonRpcIpcConfiguration.isEnabled()) {
Map<String, JsonRpcMethod> ipcMethods =
final Map<String, JsonRpcMethod> ipcMethods =
jsonRpcMethods(
protocolSchedule,
context,
@ -1023,9 +1022,10 @@ public class RunnerBuilder {
consensusEngineServer);
methods.putAll(besuController.getAdditionalJsonRpcMethods(jsonRpcApis));
var pluginMethods = rpcEndpointServiceImpl.getPluginMethods(jsonRpcConfiguration.getRpcApis());
final var pluginMethods =
rpcEndpointServiceImpl.getPluginMethods(jsonRpcConfiguration.getRpcApis());
var overriddenMethods =
final var overriddenMethods =
methods.keySet().stream().filter(pluginMethods::containsKey).collect(Collectors.toList());
if (overriddenMethods.size() > 0) {
throw new RuntimeException("You can not override built in methods " + overriddenMethods);
@ -1176,4 +1176,9 @@ public class RunnerBuilder {
this.minPeers = minPeers;
return this;
}
public RunnerBuilder legacyForkId(final boolean legacyEth64ForkIdEnabled) {
this.legacyForkIdEnabled = legacyEth64ForkIdEnabled;
return this;
}
}

@ -1425,7 +1425,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
besuPluginContext.beforeExternalServices();
var runner = buildRunner();
final var runner = buildRunner();
runner.startExternalServices();
startPlugins();
@ -1469,7 +1469,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
final String generateCompletionSubcommandName = "generate-completion";
commandLine.addSubcommand(
generateCompletionSubcommandName, AutoComplete.GenerateCompletion.class);
CommandLine generateCompletionSubcommand =
final CommandLine generateCompletionSubcommand =
commandLine.getSubcommands().get(generateCompletionSubcommandName);
generateCompletionSubcommand.getCommandSpec().usageMessage().hidden(true);
}
@ -1849,7 +1849,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
public void validateRpcOptionsParams() {
Predicate<String> configuredApis =
final Predicate<String> configuredApis =
apiName ->
Arrays.stream(RpcApis.values())
.anyMatch(builtInApi -> apiName.equals(builtInApi.name()))
@ -2176,7 +2176,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
private JsonRpcConfiguration createEngineJsonRpcConfiguration(
final Integer listenPort, final List<String> allowCallsFrom) {
JsonRpcConfiguration engineConfig =
final JsonRpcConfiguration engineConfig =
jsonRpcConfiguration(listenPort, Arrays.asList("ENGINE", "ETH"), allowCallsFrom);
engineConfig.setEnabled(isEngineApiEnabled());
if (!engineRPCOptionGroup.isEngineAuthDisabled) {
@ -2344,14 +2344,14 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
+ ")");
}
for (String cipherSuite : jsonRPCHttpOptionGroup.rpcHttpTlsCipherSuites) {
if (!getJDKEnabledCypherSuites().contains(cipherSuite)) {
for (final String cipherSuite : jsonRPCHttpOptionGroup.rpcHttpTlsCipherSuites) {
if (!getJDKEnabledCipherSuites().contains(cipherSuite)) {
throw new ParameterException(
commandLine, "Invalid TLS cipher suite specified " + cipherSuite);
}
}
jsonRPCHttpOptionGroup.rpcHttpTlsCipherSuites.retainAll(getJDKEnabledCypherSuites());
jsonRPCHttpOptionGroup.rpcHttpTlsCipherSuites.retainAll(getJDKEnabledCipherSuites());
return Optional.of(
TlsConfiguration.Builder.aTlsConfiguration()
@ -2864,6 +2864,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.getValue())
.randomPeerPriority(p2PDiscoveryOptionGroup.randomPeerPriority)
.networkingConfiguration(unstableNetworkingOptions.toDomainObject())
.legacyForkId(unstableEthProtocolOptions.toDomainObject().isLegacyEth64ForkIdEnabled())
.graphQLConfiguration(graphQLConfiguration)
.jsonRpcConfiguration(jsonRpcConfiguration)
.engineJsonRpcConfiguration(engineJsonRpcConfiguration)
@ -2883,7 +2884,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.ethstatsUrl(ethstatsOptions.getEthstatsUrl())
.ethstatsContact(ethstatsOptions.getEthstatsContact())
.storageProvider(keyValueStorageProvider(keyValueStorageName))
.forkIdSupplier(() -> besuController.getProtocolManager().getForkIdAsBytesList())
.rpcEndpointService(rpcEndpointServiceImpl)
.build();
@ -3013,7 +3013,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
try (final InputStream genesisFileInputStream =
EthNetworkConfig.class.getResourceAsStream(networkName.getGenesisFile())) {
return new String(genesisFileInputStream.readAllBytes(), UTF_8);
} catch (IOException | NullPointerException e) {
} catch (final IOException | NullPointerException e) {
throw new IllegalStateException(e);
}
}
@ -3300,24 +3300,24 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
return engineRPCOptionGroup.overrideEngineRpcEnabled || isMergeEnabled();
}
public static List<String> getJDKEnabledCypherSuites() {
public static List<String> getJDKEnabledCipherSuites() {
try {
SSLContext context = SSLContext.getInstance("TLS");
final SSLContext context = SSLContext.getInstance("TLS");
context.init(null, null, null);
SSLEngine engine = context.createSSLEngine();
final SSLEngine engine = context.createSSLEngine();
return Arrays.asList(engine.getEnabledCipherSuites());
} catch (KeyManagementException | NoSuchAlgorithmException e) {
} catch (final KeyManagementException | NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
public static List<String> getJDKEnabledProtocols() {
try {
SSLContext context = SSLContext.getInstance("TLS");
final SSLContext context = SSLContext.getInstance("TLS");
context.init(null, null, null);
SSLEngine engine = context.createSSLEngine();
final SSLEngine engine = context.createSSLEngine();
return Arrays.asList(engine.getEnabledProtocols());
} catch (KeyManagementException | NoSuchAlgorithmException e) {
} catch (final KeyManagementException | NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}

@ -33,6 +33,7 @@ public class NetworkingOptions implements CLIOptions<NetworkingConfiguration> {
private final String DNS_DISCOVERY_SERVER_OVERRIDE_FLAG = "--Xp2p-dns-discovery-server";
private final String DISCOVERY_PROTOCOL_V5_ENABLED = "--Xv5-discovery-enabled";
private final String P2P_PEER_LOWER_BOUND_FLAG = "--Xp2p-peer-lower-bound";
public static final String FILTER_ON_ENR_FORK_ID = "--Xfilter-on-enr-fork-id";
@CommandLine.Option(
names = INITIATE_CONNECTIONS_FREQUENCY_FLAG,
@ -68,6 +69,13 @@ public class NetworkingOptions implements CLIOptions<NetworkingConfiguration> {
description = "Whether to enable P2P Discovery Protocol v5 (default: ${DEFAULT-VALUE})")
private final Boolean isPeerDiscoveryV5Enabled = false;
@CommandLine.Option(
names = FILTER_ON_ENR_FORK_ID,
hidden = true,
defaultValue = "false",
description = "Whether to enable filtering of peers based on the ENR field ForkId)")
private final Boolean filterOnEnrForkId = false;
@CommandLine.Option(
hidden = true,
names = {P2P_PEER_LOWER_BOUND_FLAG},
@ -99,6 +107,7 @@ public class NetworkingOptions implements CLIOptions<NetworkingConfiguration> {
config.setInitiateConnectionsFrequency(initiateConnectionsFrequencySec);
config.setDnsDiscoveryServerOverride(dnsDiscoveryServerOverride);
config.getDiscovery().setDiscoveryV5Enabled(isPeerDiscoveryV5Enabled);
config.getDiscovery().setFilterOnEnrForkId(filterOnEnrForkId);
config.getRlpx().setPeerLowerBound(peerLowerBound);
return config;
}

@ -26,8 +26,8 @@ import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.config.GenesisConfigOptions;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.chain.GenesisState;
import org.hyperledger.besu.ethereum.eth.manager.ForkId;
import org.hyperledger.besu.ethereum.eth.manager.ForkIdManager;
import org.hyperledger.besu.ethereum.forkid.ForkId;
import org.hyperledger.besu.ethereum.forkid.ForkIdManager;
import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.MutableProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
@ -42,163 +42,177 @@ import java.util.stream.Stream;
import com.google.common.collect.Streams;
import org.apache.tuweni.bytes.Bytes;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
@RunWith(Enclosed.class)
public class ForkIdsTest {
@Parameterized.Parameter public NetworkName chainName;
@Parameterized.Parameter(1)
public List<ForkId> expectedForkIds;
@Parameterized.Parameters(name = "{0}")
public static Collection<Object[]> parameters() {
return List.of(
new Object[] {
NetworkName.SEPOLIA,
List.of(
new ForkId(Bytes.ofUnsignedInt(0xfe3366e7L), 1735371L),
new ForkId(Bytes.ofUnsignedInt(0xb96cbd13L), 0L),
new ForkId(Bytes.ofUnsignedInt(0xb96cbd13L), 0L))
},
new Object[] {
NetworkName.ROPSTEN,
List.of(
new ForkId(Bytes.ofUnsignedInt(0x30c7ddbcL), 10L),
new ForkId(Bytes.ofUnsignedInt(0x63760190L), 1700000L),
new ForkId(Bytes.ofUnsignedInt(0x3ea159c7L), 4230000L),
new ForkId(Bytes.ofUnsignedInt(0x97b544f3L), 4939394L),
new ForkId(Bytes.ofUnsignedInt(0xd6e2149bL), 6485846L),
new ForkId(Bytes.ofUnsignedInt(0x4bc66396L), 7117117L),
new ForkId(Bytes.ofUnsignedInt(0x6727ef90L), 9812189L),
new ForkId(Bytes.ofUnsignedInt(0xa157d377L), 10499401L),
new ForkId(Bytes.ofUnsignedInt(0x7119b6b3L), 0L),
new ForkId(Bytes.ofUnsignedInt(0x7119b6b3L), 0L))
},
new Object[] {
NetworkName.RINKEBY,
List.of(
new ForkId(Bytes.ofUnsignedInt(0x3b8e0691L), 1L),
new ForkId(Bytes.ofUnsignedInt(0x60949295L), 2L),
new ForkId(Bytes.ofUnsignedInt(0x8bde40ddL), 3L),
new ForkId(Bytes.ofUnsignedInt(0xcb3a64bbL), 1035301L),
new ForkId(Bytes.ofUnsignedInt(0x8d748b57L), 3660663L),
new ForkId(Bytes.ofUnsignedInt(0xe49cab14L), 4321234L),
new ForkId(Bytes.ofUnsignedInt(0xafec6b27L), 5435345L),
new ForkId(Bytes.ofUnsignedInt(0xcbdb8838L), 8290928L),
new ForkId(Bytes.ofUnsignedInt(0x6910c8bdL), 8897988L),
new ForkId(Bytes.ofUnsignedInt(0x8e29f2f3L), 0L),
new ForkId(Bytes.ofUnsignedInt(0x8e29f2f3L), 0L))
},
new Object[] {
NetworkName.GOERLI,
List.of(
new ForkId(Bytes.ofUnsignedInt(0xa3f5ab08L), 1561651L),
new ForkId(Bytes.ofUnsignedInt(0xc25efa5cL), 4460644L),
new ForkId(Bytes.ofUnsignedInt(0x757a1c47L), 5062605L),
new ForkId(Bytes.ofUnsignedInt(0xb8c6299dL), 0L),
new ForkId(Bytes.ofUnsignedInt(0xb8c6299dL), 0L))
},
new Object[] {
NetworkName.SHANDONG,
List.of(
new ForkId(Bytes.ofUnsignedInt(0x0459e09dL), 0L),
new ForkId(Bytes.ofUnsignedInt(0x0459e09dL), 0L))
},
new Object[] {
NetworkName.MAINNET,
List.of(
new ForkId(Bytes.ofUnsignedInt(0xfc64ec04L), 1150000L),
new ForkId(Bytes.ofUnsignedInt(0x97c2c34cL), 1920000L),
new ForkId(Bytes.ofUnsignedInt(0x91d1f948L), 2463000L),
new ForkId(Bytes.ofUnsignedInt(0x91d1f948L), 2463000L),
new ForkId(Bytes.ofUnsignedInt(0x91d1f948L), 2463000L),
new ForkId(Bytes.ofUnsignedInt(0x7a64da13L), 2675000L),
new ForkId(Bytes.ofUnsignedInt(0x3edd5b10L), 4370000L),
new ForkId(Bytes.ofUnsignedInt(0xa00bc324L), 7280000L),
new ForkId(Bytes.ofUnsignedInt(0x668db0afL), 9069000L),
new ForkId(Bytes.ofUnsignedInt(0x879d6e30L), 9200000L),
new ForkId(Bytes.ofUnsignedInt(0xe029e991L), 12244000L),
new ForkId(Bytes.ofUnsignedInt(0xeb440f6L), 12965000L),
new ForkId(Bytes.ofUnsignedInt(0xb715077dL), 13773000L),
new ForkId(Bytes.ofUnsignedInt(0x20c327fcL), 15050000L),
new ForkId(Bytes.ofUnsignedInt(0xf0afd0e3L), 0L),
new ForkId(Bytes.ofUnsignedInt(0xf0afd0e3L), 0L))
},
new Object[] {
NetworkName.MORDOR,
List.of(
new ForkId(Bytes.ofUnsignedInt(0x175782aaL), 301243L),
new ForkId(Bytes.ofUnsignedInt(0x604f6ee1L), 999983L),
new ForkId(Bytes.ofUnsignedInt(0xf42f5539L), 2520000L),
new ForkId(Bytes.ofUnsignedInt(0x66b5c286L), 3985893),
new ForkId(Bytes.ofUnsignedInt(0x92b323e0L), 5520000L),
new ForkId(Bytes.ofUnsignedInt(0x8c9b1797L), 0L),
new ForkId(Bytes.ofUnsignedInt(0x8c9b1797L), 0L))
},
new Object[] {
NetworkName.KOTTI,
List.of(
new ForkId(Bytes.ofUnsignedInt(0x550152eL), 716617L),
new ForkId(Bytes.ofUnsignedInt(0xa3270822L), 1705549L),
new ForkId(Bytes.ofUnsignedInt(0x8f3698e0L), 2200013L),
new ForkId(Bytes.ofUnsignedInt(0x6f402821L), 4368634),
new ForkId(Bytes.ofUnsignedInt(0xf03e54e7L), 5578000L),
new ForkId(Bytes.ofUnsignedInt(0xc5459816L), 0L),
new ForkId(Bytes.ofUnsignedInt(0xc5459816L), 0L))
},
new Object[] {
NetworkName.CLASSIC,
List.of(
new ForkId(Bytes.ofUnsignedInt(0xfc64ec04L), 1150000L),
new ForkId(Bytes.ofUnsignedInt(0x97c2c34cL), 2500000L),
new ForkId(Bytes.ofUnsignedInt(0x97c2c34cL), 2500000L),
new ForkId(Bytes.ofUnsignedInt(0x97c2c34cL), 2500000L),
new ForkId(Bytes.ofUnsignedInt(0xdb06803fL), 3000000L),
new ForkId(Bytes.ofUnsignedInt(0xaff4bed4L), 5000000L),
new ForkId(Bytes.ofUnsignedInt(0xf79a63c0L), 5900000L),
new ForkId(Bytes.ofUnsignedInt(0x744899d6L), 8772000L),
new ForkId(Bytes.ofUnsignedInt(0x518b59c6L), 9573000L),
new ForkId(Bytes.ofUnsignedInt(0x7ba22882L), 10500839L),
new ForkId(Bytes.ofUnsignedInt(0x9007bfccL), 11700000L),
new ForkId(Bytes.ofUnsignedInt(0xdb63a1caL), 13189133),
new ForkId(Bytes.ofUnsignedInt(0x0f6bf187L), 14525000L),
new ForkId(Bytes.ofUnsignedInt(0x7fd1bb25L), 0L),
new ForkId(Bytes.ofUnsignedInt(0x7fd1bb25L), 0L))
});
public static class NotParameterized {
@Test
public void testFromRaw() {
final ForkId forkId = new ForkId(Bytes.ofUnsignedInt(0xfe3366e7L), 1735371L);
final List<List<Bytes>> forkIdAsBytesList = List.of(forkId.getForkIdAsBytesList());
assertThat(ForkId.fromRawForkId(forkIdAsBytesList).get()).isEqualTo(forkId);
}
}
@Test
public void testForkId() {
final GenesisConfigFile genesisConfigFile =
GenesisConfigFile.fromConfig(EthNetworkConfig.jsonConfig(chainName));
final GenesisConfigOptions configOptions = genesisConfigFile.getConfigOptions();
final ProtocolSchedule schedule =
MainnetProtocolSchedule.fromConfig(configOptions, EvmConfiguration.DEFAULT);
final GenesisState genesisState = GenesisState.fromConfig(genesisConfigFile, schedule);
final Blockchain mockBlockchain = mock(Blockchain.class);
when(mockBlockchain.getGenesisBlock()).thenReturn(genesisState.getBlock());
final AtomicLong blockNumber = new AtomicLong();
when(mockBlockchain.getChainHeadBlockNumber()).thenAnswer(o -> blockNumber.get());
final ForkIdManager forkIdManager =
new ForkIdManager(mockBlockchain, genesisConfigFile.getForks(), false);
final var actualForkIds =
Streams.concat(
((MutableProtocolSchedule) schedule).streamMilestoneBlocks(),
Stream.of(Long.MAX_VALUE))
.map(
block -> {
blockNumber.set(block);
return forkIdManager.getForkIdForChainHead();
})
.collect(Collectors.toList());
assertThat(actualForkIds).containsExactlyElementsOf(expectedForkIds);
@RunWith(Parameterized.class)
public static class ParametrizedForkIdTest {
@Parameterized.Parameter public NetworkName chainName;
@Parameterized.Parameter(1)
public List<ForkId> expectedForkIds;
@Parameterized.Parameters(name = "{0}")
public static Collection<Object[]> parameters() {
return List.of(
new Object[] {
NetworkName.SEPOLIA,
List.of(
new ForkId(Bytes.ofUnsignedInt(0xfe3366e7L), 1735371L),
new ForkId(Bytes.ofUnsignedInt(0xb96cbd13L), 0L),
new ForkId(Bytes.ofUnsignedInt(0xb96cbd13L), 0L))
},
new Object[] {
NetworkName.ROPSTEN,
List.of(
new ForkId(Bytes.ofUnsignedInt(0x30c7ddbcL), 10L),
new ForkId(Bytes.ofUnsignedInt(0x63760190L), 1700000L),
new ForkId(Bytes.ofUnsignedInt(0x3ea159c7L), 4230000L),
new ForkId(Bytes.ofUnsignedInt(0x97b544f3L), 4939394L),
new ForkId(Bytes.ofUnsignedInt(0xd6e2149bL), 6485846L),
new ForkId(Bytes.ofUnsignedInt(0x4bc66396L), 7117117L),
new ForkId(Bytes.ofUnsignedInt(0x6727ef90L), 9812189L),
new ForkId(Bytes.ofUnsignedInt(0xa157d377L), 10499401L),
new ForkId(Bytes.ofUnsignedInt(0x7119b6b3L), 0L),
new ForkId(Bytes.ofUnsignedInt(0x7119b6b3L), 0L))
},
new Object[] {
NetworkName.RINKEBY,
List.of(
new ForkId(Bytes.ofUnsignedInt(0x3b8e0691L), 1L),
new ForkId(Bytes.ofUnsignedInt(0x60949295L), 2L),
new ForkId(Bytes.ofUnsignedInt(0x8bde40ddL), 3L),
new ForkId(Bytes.ofUnsignedInt(0xcb3a64bbL), 1035301L),
new ForkId(Bytes.ofUnsignedInt(0x8d748b57L), 3660663L),
new ForkId(Bytes.ofUnsignedInt(0xe49cab14L), 4321234L),
new ForkId(Bytes.ofUnsignedInt(0xafec6b27L), 5435345L),
new ForkId(Bytes.ofUnsignedInt(0xcbdb8838L), 8290928L),
new ForkId(Bytes.ofUnsignedInt(0x6910c8bdL), 8897988L),
new ForkId(Bytes.ofUnsignedInt(0x8e29f2f3L), 0L),
new ForkId(Bytes.ofUnsignedInt(0x8e29f2f3L), 0L))
},
new Object[] {
NetworkName.GOERLI,
List.of(
new ForkId(Bytes.ofUnsignedInt(0xa3f5ab08L), 1561651L),
new ForkId(Bytes.ofUnsignedInt(0xc25efa5cL), 4460644L),
new ForkId(Bytes.ofUnsignedInt(0x757a1c47L), 5062605L),
new ForkId(Bytes.ofUnsignedInt(0xb8c6299dL), 0L),
new ForkId(Bytes.ofUnsignedInt(0xb8c6299dL), 0L))
},
new Object[] {
NetworkName.SHANDONG,
List.of(
new ForkId(Bytes.ofUnsignedInt(0x0459e09dL), 0L),
new ForkId(Bytes.ofUnsignedInt(0x0459e09dL), 0L))
},
new Object[] {
NetworkName.MAINNET,
List.of(
new ForkId(Bytes.ofUnsignedInt(0xfc64ec04L), 1150000L),
new ForkId(Bytes.ofUnsignedInt(0x97c2c34cL), 1920000L),
new ForkId(Bytes.ofUnsignedInt(0x91d1f948L), 2463000L),
new ForkId(Bytes.ofUnsignedInt(0x91d1f948L), 2463000L),
new ForkId(Bytes.ofUnsignedInt(0x91d1f948L), 2463000L),
new ForkId(Bytes.ofUnsignedInt(0x7a64da13L), 2675000L),
new ForkId(Bytes.ofUnsignedInt(0x3edd5b10L), 4370000L),
new ForkId(Bytes.ofUnsignedInt(0xa00bc324L), 7280000L),
new ForkId(Bytes.ofUnsignedInt(0x668db0afL), 9069000L),
new ForkId(Bytes.ofUnsignedInt(0x879d6e30L), 9200000L),
new ForkId(Bytes.ofUnsignedInt(0xe029e991L), 12244000L),
new ForkId(Bytes.ofUnsignedInt(0xeb440f6L), 12965000L),
new ForkId(Bytes.ofUnsignedInt(0xb715077dL), 13773000L),
new ForkId(Bytes.ofUnsignedInt(0x20c327fcL), 15050000L),
new ForkId(Bytes.ofUnsignedInt(0xf0afd0e3L), 0L),
new ForkId(Bytes.ofUnsignedInt(0xf0afd0e3L), 0L))
},
new Object[] {
NetworkName.MORDOR,
List.of(
new ForkId(Bytes.ofUnsignedInt(0x175782aaL), 301243L),
new ForkId(Bytes.ofUnsignedInt(0x604f6ee1L), 999983L),
new ForkId(Bytes.ofUnsignedInt(0xf42f5539L), 2520000L),
new ForkId(Bytes.ofUnsignedInt(0x66b5c286L), 3985893),
new ForkId(Bytes.ofUnsignedInt(0x92b323e0L), 5520000L),
new ForkId(Bytes.ofUnsignedInt(0x8c9b1797L), 0L),
new ForkId(Bytes.ofUnsignedInt(0x8c9b1797L), 0L))
},
new Object[] {
NetworkName.KOTTI,
List.of(
new ForkId(Bytes.ofUnsignedInt(0x550152eL), 716617L),
new ForkId(Bytes.ofUnsignedInt(0xa3270822L), 1705549L),
new ForkId(Bytes.ofUnsignedInt(0x8f3698e0L), 2200013L),
new ForkId(Bytes.ofUnsignedInt(0x6f402821L), 4368634),
new ForkId(Bytes.ofUnsignedInt(0xf03e54e7L), 5578000L),
new ForkId(Bytes.ofUnsignedInt(0xc5459816L), 0L),
new ForkId(Bytes.ofUnsignedInt(0xc5459816L), 0L))
},
new Object[] {
NetworkName.CLASSIC,
List.of(
new ForkId(Bytes.ofUnsignedInt(0xfc64ec04L), 1150000L),
new ForkId(Bytes.ofUnsignedInt(0x97c2c34cL), 2500000L),
new ForkId(Bytes.ofUnsignedInt(0x97c2c34cL), 2500000L),
new ForkId(Bytes.ofUnsignedInt(0x97c2c34cL), 2500000L),
new ForkId(Bytes.ofUnsignedInt(0xdb06803fL), 3000000L),
new ForkId(Bytes.ofUnsignedInt(0xaff4bed4L), 5000000L),
new ForkId(Bytes.ofUnsignedInt(0xf79a63c0L), 5900000L),
new ForkId(Bytes.ofUnsignedInt(0x744899d6L), 8772000L),
new ForkId(Bytes.ofUnsignedInt(0x518b59c6L), 9573000L),
new ForkId(Bytes.ofUnsignedInt(0x7ba22882L), 10500839L),
new ForkId(Bytes.ofUnsignedInt(0x9007bfccL), 11700000L),
new ForkId(Bytes.ofUnsignedInt(0xdb63a1caL), 13189133),
new ForkId(Bytes.ofUnsignedInt(0x0f6bf187L), 14525000L),
new ForkId(Bytes.ofUnsignedInt(0x7fd1bb25L), 0L),
new ForkId(Bytes.ofUnsignedInt(0x7fd1bb25L), 0L))
});
}
@Test
public void testForkId() {
final GenesisConfigFile genesisConfigFile =
GenesisConfigFile.fromConfig(EthNetworkConfig.jsonConfig(chainName));
final GenesisConfigOptions configOptions = genesisConfigFile.getConfigOptions();
final ProtocolSchedule schedule =
MainnetProtocolSchedule.fromConfig(configOptions, EvmConfiguration.DEFAULT);
final GenesisState genesisState = GenesisState.fromConfig(genesisConfigFile, schedule);
final Blockchain mockBlockchain = mock(Blockchain.class);
when(mockBlockchain.getGenesisBlock()).thenReturn(genesisState.getBlock());
final AtomicLong blockNumber = new AtomicLong();
when(mockBlockchain.getChainHeadBlockNumber()).thenAnswer(o -> blockNumber.get());
final ForkIdManager forkIdManager =
new ForkIdManager(mockBlockchain, genesisConfigFile.getForks(), false);
final var actualForkIds =
Streams.concat(
((MutableProtocolSchedule) schedule).streamMilestoneBlocks(),
Stream.of(Long.MAX_VALUE))
.map(
block -> {
blockNumber.set(block);
return forkIdManager.getForkIdForChainHead();
})
.collect(Collectors.toList());
assertThat(actualForkIds).containsExactlyElementsOf(expectedForkIds);
}
}
}

@ -25,6 +25,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.config.GenesisConfigOptions;
import org.hyperledger.besu.config.MergeConfigOptions;
import org.hyperledger.besu.consensus.common.bft.BftEventQueue;
import org.hyperledger.besu.consensus.common.bft.network.PeerConnectionTracker;
@ -36,6 +37,7 @@ import org.hyperledger.besu.controller.BesuController;
import org.hyperledger.besu.crypto.KeyPairSecurityModule;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.crypto.SECP256K1;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.api.graphql.GraphQLConfiguration;
import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration;
@ -116,7 +118,11 @@ public final class RunnerBuilderTest {
when(ethProtocolManager.ethContext()).thenReturn(ethContext);
when(subProtocolConfiguration.getSubProtocols())
.thenReturn(Collections.singletonList(new IbftSubProtocol()));
when(protocolContext.getBlockchain()).thenReturn(mock(DefaultBlockchain.class));
final DefaultBlockchain blockchain = mock(DefaultBlockchain.class);
when(protocolContext.getBlockchain()).thenReturn(blockchain);
final Block block = mock(Block.class);
when(blockchain.getGenesisBlock()).thenReturn(block);
when(block.getHash()).thenReturn(Hash.ZERO);
when(besuController.getProtocolManager()).thenReturn(ethProtocolManager);
when(besuController.getSubProtocolConfiguration()).thenReturn(subProtocolConfiguration);
@ -128,6 +134,10 @@ public final class RunnerBuilderTest {
when(besuController.getTransactionPool()).thenReturn(mock(TransactionPool.class));
when(besuController.getSynchronizer()).thenReturn(mock(Synchronizer.class));
when(besuController.getMiningCoordinator()).thenReturn(mock(MiningCoordinator.class));
when(besuController.getMiningCoordinator()).thenReturn(mock(MergeMiningCoordinator.class));
final GenesisConfigOptions genesisConfigOptions = mock(GenesisConfigOptions.class);
when(genesisConfigOptions.getForks()).thenReturn(Collections.emptyList());
when(besuController.getGenesisConfigOptions()).thenReturn(genesisConfigOptions);
}
@Test
@ -154,7 +164,6 @@ public final class RunnerBuilderTest {
.vertx(vertx)
.dataDir(dataDir.getRoot().toPath())
.storageProvider(mock(KeyValueStorageProvider.class))
.forkIdSupplier(() -> Collections.singletonList(Bytes.EMPTY))
.rpcEndpointService(new RpcEndpointServiceImpl())
.build();
runner.startEthereumMainLoop();
@ -199,7 +208,6 @@ public final class RunnerBuilderTest {
.vertx(Vertx.vertx())
.dataDir(dataDir.getRoot().toPath())
.storageProvider(storageProvider)
.forkIdSupplier(() -> Collections.singletonList(Bytes.EMPTY))
.rpcEndpointService(new RpcEndpointServiceImpl())
.build();
runner.startEthereumMainLoop();
@ -225,11 +233,11 @@ public final class RunnerBuilderTest {
@Test
public void whenEngineApiAddedListensOnDefaultPort() {
JsonRpcConfiguration jrpc = JsonRpcConfiguration.createDefault();
final JsonRpcConfiguration jrpc = JsonRpcConfiguration.createDefault();
jrpc.setEnabled(true);
JsonRpcConfiguration engine = JsonRpcConfiguration.createEngineDefault();
final JsonRpcConfiguration engine = JsonRpcConfiguration.createEngineDefault();
engine.setEnabled(true);
EthNetworkConfig mockMainnet = mock(EthNetworkConfig.class);
final EthNetworkConfig mockMainnet = mock(EthNetworkConfig.class);
when(mockMainnet.getNetworkId()).thenReturn(BigInteger.ONE);
MergeConfigOptions.setMergeEnabled(true);
when(besuController.getMiningCoordinator()).thenReturn(mock(MergeMiningCoordinator.class));
@ -255,7 +263,6 @@ public final class RunnerBuilderTest {
.vertx(Vertx.vertx())
.dataDir(dataDir.getRoot().toPath())
.storageProvider(mock(KeyValueStorageProvider.class))
.forkIdSupplier(() -> Collections.singletonList(Bytes.EMPTY))
.rpcEndpointService(new RpcEndpointServiceImpl())
.besuPluginContext(mock(BesuPluginContextImpl.class))
.build();
@ -266,13 +273,13 @@ public final class RunnerBuilderTest {
@Test
public void whenEngineApiAddedWebSocketReadyOnSamePort() {
WebSocketConfiguration wsRpc = WebSocketConfiguration.createDefault();
final WebSocketConfiguration wsRpc = WebSocketConfiguration.createDefault();
wsRpc.setEnabled(true);
EthNetworkConfig mockMainnet = mock(EthNetworkConfig.class);
final EthNetworkConfig mockMainnet = mock(EthNetworkConfig.class);
when(mockMainnet.getNetworkId()).thenReturn(BigInteger.ONE);
MergeConfigOptions.setMergeEnabled(true);
when(besuController.getMiningCoordinator()).thenReturn(mock(MergeMiningCoordinator.class));
JsonRpcConfiguration engineConf = JsonRpcConfiguration.createEngineDefault();
final JsonRpcConfiguration engineConf = JsonRpcConfiguration.createEngineDefault();
engineConf.setEnabled(true);
final Runner runner =
@ -296,7 +303,6 @@ public final class RunnerBuilderTest {
.vertx(Vertx.vertx())
.dataDir(dataDir.getRoot().toPath())
.storageProvider(mock(KeyValueStorageProvider.class))
.forkIdSupplier(() -> Collections.singletonList(Bytes.EMPTY))
.rpcEndpointService(new RpcEndpointServiceImpl())
.besuPluginContext(mock(BesuPluginContextImpl.class))
.build();
@ -306,13 +312,13 @@ public final class RunnerBuilderTest {
@Test
public void whenEngineApiAddedEthSubscribeAvailable() {
WebSocketConfiguration wsRpc = WebSocketConfiguration.createDefault();
final WebSocketConfiguration wsRpc = WebSocketConfiguration.createDefault();
wsRpc.setEnabled(true);
EthNetworkConfig mockMainnet = mock(EthNetworkConfig.class);
final EthNetworkConfig mockMainnet = mock(EthNetworkConfig.class);
when(mockMainnet.getNetworkId()).thenReturn(BigInteger.ONE);
MergeConfigOptions.setMergeEnabled(true);
when(besuController.getMiningCoordinator()).thenReturn(mock(MergeMiningCoordinator.class));
JsonRpcConfiguration engineConf = JsonRpcConfiguration.createEngineDefault();
final JsonRpcConfiguration engineConf = JsonRpcConfiguration.createEngineDefault();
engineConf.setEnabled(true);
final Runner runner =
@ -336,7 +342,6 @@ public final class RunnerBuilderTest {
.vertx(Vertx.vertx())
.dataDir(dataDir.getRoot().toPath())
.storageProvider(mock(KeyValueStorageProvider.class))
.forkIdSupplier(() -> Collections.singletonList(Bytes.EMPTY))
.rpcEndpointService(new RpcEndpointServiceImpl())
.besuPluginContext(mock(BesuPluginContextImpl.class))
.build();
@ -349,14 +354,13 @@ public final class RunnerBuilderTest {
@Test
public void noEngineApiNoServiceForMethods() {
JsonRpcConfiguration defaultRpcConfig = JsonRpcConfiguration.createDefault();
final JsonRpcConfiguration defaultRpcConfig = JsonRpcConfiguration.createDefault();
defaultRpcConfig.setEnabled(true);
WebSocketConfiguration defaultWebSockConfig = WebSocketConfiguration.createDefault();
final WebSocketConfiguration defaultWebSockConfig = WebSocketConfiguration.createDefault();
defaultWebSockConfig.setEnabled(true);
EthNetworkConfig mockMainnet = mock(EthNetworkConfig.class);
final EthNetworkConfig mockMainnet = mock(EthNetworkConfig.class);
when(mockMainnet.getNetworkId()).thenReturn(BigInteger.ONE);
MergeConfigOptions.setMergeEnabled(true);
when(besuController.getMiningCoordinator()).thenReturn(mock(MergeMiningCoordinator.class));
final Runner runner =
new RunnerBuilder()
@ -378,7 +382,6 @@ public final class RunnerBuilderTest {
.vertx(Vertx.vertx())
.dataDir(dataDir.getRoot().toPath())
.storageProvider(mock(KeyValueStorageProvider.class))
.forkIdSupplier(() -> Collections.singletonList(Bytes.EMPTY))
.rpcEndpointService(new RpcEndpointServiceImpl())
.besuPluginContext(mock(BesuPluginContextImpl.class))
.build();
@ -389,16 +392,16 @@ public final class RunnerBuilderTest {
@Test
public void assertTransitionStratumConfiguration() {
JsonRpcConfiguration jrpc = JsonRpcConfiguration.createDefault();
final JsonRpcConfiguration jrpc = JsonRpcConfiguration.createDefault();
jrpc.setEnabled(true);
JsonRpcConfiguration engine = JsonRpcConfiguration.createEngineDefault();
final JsonRpcConfiguration engine = JsonRpcConfiguration.createEngineDefault();
engine.setEnabled(true);
EthNetworkConfig mockMainnet = mock(EthNetworkConfig.class);
final EthNetworkConfig mockMainnet = mock(EthNetworkConfig.class);
when(mockMainnet.getNetworkId()).thenReturn(BigInteger.ONE);
MergeConfigOptions.setMergeEnabled(true);
MiningParameters mockMiningParams = besuController.getMiningParameters();
final MiningParameters mockMiningParams = besuController.getMiningParameters();
when(mockMiningParams.isStratumMiningEnabled()).thenReturn(true);
TransitionCoordinator mockTransitionCoordinator =
final TransitionCoordinator mockTransitionCoordinator =
spy(
new TransitionCoordinator(
mock(PoWMiningCoordinator.class), mock(MergeMiningCoordinator.class)));
@ -424,7 +427,6 @@ public final class RunnerBuilderTest {
.vertx(Vertx.vertx())
.dataDir(dataDir.getRoot().toPath())
.storageProvider(mock(KeyValueStorageProvider.class))
.forkIdSupplier(() -> Collections.singletonList(Bytes.EMPTY))
.rpcEndpointService(new RpcEndpointServiceImpl())
.besuPluginContext(mock(BesuPluginContextImpl.class))
.build();

@ -93,7 +93,6 @@ import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256;
import org.awaitility.Awaitility;
import org.junit.After;
@ -224,7 +223,6 @@ public final class RunnerTest {
.permissioningService(new PermissioningServiceImpl())
.staticNodes(emptySet())
.storageProvider(new InMemoryKeyValueStorageProvider())
.forkIdSupplier(() -> Collections.singletonList(Bytes.EMPTY))
.rpcEndpointService(new RpcEndpointServiceImpl());
Runner runnerBehind = null;
@ -240,7 +238,6 @@ public final class RunnerTest {
.dataDir(dbAhead)
.pidPath(pidPath)
.besuPluginContext(new BesuPluginContextImpl())
.forkIdSupplier(() -> controllerAhead.getProtocolManager().getForkIdAsBytesList())
.rpcEndpointService(new RpcEndpointServiceImpl())
.build();
try {
@ -295,7 +292,6 @@ public final class RunnerTest {
.metricsConfiguration(behindMetricsConfiguration)
.dataDir(temp.newFolder().toPath())
.metricsSystem(noOpMetricsSystem)
.forkIdSupplier(() -> controllerBehind.getProtocolManager().getForkIdAsBytesList())
.build();
runnerBehind.startExternalServices();

@ -280,8 +280,8 @@ public abstract class CommandTestAbstract {
when(mockRunnerBuilder.ethstatsUrl(anyString())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.ethstatsContact(anyString())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.storageProvider(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.forkIdSupplier(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.rpcEndpointService(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.legacyForkId(anyBoolean())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.build()).thenReturn(mockRunner);
final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance();
@ -377,11 +377,11 @@ public abstract class CommandTestAbstract {
privacyPluginService);
besuCommands.add(besuCommand);
File defaultKeyFile =
final File defaultKeyFile =
KeyPairUtil.getDefaultKeyFile(DefaultCommandValues.getDefaultBesuDataPath(besuCommand));
try {
Files.writeString(defaultKeyFile.toPath(), keyPair.getPrivateKey().toString());
} catch (IOException e) {
} catch (final IOException e) {
throw new RuntimeException(e);
}
besuCommand.setBesuConfiguration(commonPluginConfiguration);

@ -152,6 +152,42 @@ public class NetworkingOptionsTest
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void checkFilterByForkIdNotSet() {
final TestBesuCommand cmd = parseCommand();
final NetworkingOptions options = cmd.getNetworkingOptions();
final NetworkingConfiguration networkingConfig = options.toDomainObject();
assertThat(networkingConfig.getDiscovery().isFilterOnEnrForkIdEnabled()).isEqualTo(false);
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void checkFilterByForkIdSet() {
final TestBesuCommand cmd = parseCommand(NetworkingOptions.FILTER_ON_ENR_FORK_ID + "=true");
final NetworkingOptions options = cmd.getNetworkingOptions();
final NetworkingConfiguration networkingConfig = options.toDomainObject();
assertThat(networkingConfig.getDiscovery().isFilterOnEnrForkIdEnabled()).isEqualTo(true);
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void checkFilterByForkIdSetToFalse() {
final TestBesuCommand cmd = parseCommand(NetworkingOptions.FILTER_ON_ENR_FORK_ID + "=false");
final NetworkingOptions options = cmd.getNetworkingOptions();
final NetworkingConfiguration networkingConfig = options.toDomainObject();
assertThat(networkingConfig.getDiscovery().isFilterOnEnrForkIdEnabled()).isEqualTo(false);
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Override
NetworkingConfiguration createDefaultDomainObject() {
return NetworkingConfiguration.create();

@ -18,9 +18,11 @@ import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.config.StubGenesisConfigOptions;
import org.hyperledger.besu.crypto.NodeKeyUtils;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.health.HealthService;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager;
@ -30,6 +32,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethodsFactory;
import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture;
@ -69,7 +73,6 @@ import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.apache.tuweni.bytes.Bytes;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@ -261,6 +264,10 @@ public class JsonRpcHttpServiceRpcApisTest {
.setRlpx(RlpxConfiguration.create().setBindPort(0))
.setDiscovery(DiscoveryConfiguration.create().setBindPort(0));
final MutableBlockchain blockchain = mock(MutableBlockchain.class);
final Block genesisBlock = mock(Block.class);
when(blockchain.getGenesisBlock()).thenReturn(genesisBlock);
when(genesisBlock.getHash()).thenReturn(Hash.ZERO);
final P2PNetwork p2pNetwork =
DefaultP2PNetwork.builder()
.supportedCapabilities(Capability.create("eth", 63))
@ -269,7 +276,8 @@ public class JsonRpcHttpServiceRpcApisTest {
.config(config)
.metricsSystem(new NoOpMetricsSystem())
.storageProvider(new InMemoryKeyValueStorageProvider())
.forkIdSupplier(() -> Collections.singletonList(Bytes.EMPTY))
.blockchain(blockchain)
.forks(Collections.emptyList())
.build();
p2pNetwork.start();
@ -412,7 +420,7 @@ public class JsonRpcHttpServiceRpcApisTest {
WebSocketConfiguration webSocketConfiguration = WebSocketConfiguration.createDefault();
P2PNetwork p2pNetwork = mock(P2PNetwork.class);
MetricsConfiguration metricsConfiguration = MetricsConfiguration.builder().build();
NatService natService = mock(NatService.class);
final NatService natService = mock(NatService.class);
if (enabledNetServices[netServices.indexOf("jsonrpc")]) {
jsonRpcConfiguration = createJsonRpcConfiguration();

@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.eth.manager;
package org.hyperledger.besu.ethereum.forkid;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.ethereum.rlp.RLPInput;
@ -21,6 +21,7 @@ import org.hyperledger.besu.util.EndianUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
@ -39,6 +40,19 @@ public class ForkId {
this(hash, Bytes.wrap(EndianUtils.longToBigEndian(next)).trimLeadingZeros());
}
public static Optional<ForkId> fromRawForkId(final Object rawForkId) {
if (rawForkId != null) {
try {
@SuppressWarnings("unchecked")
final List<List<Bytes>> typedRawForkId = (List<List<Bytes>>) rawForkId;
return Optional.of(new ForkId(typedRawForkId.get(0).get(0), typedRawForkId.get(0).get(1)));
} catch (final Exception e) {
return Optional.empty();
}
}
return Optional.empty();
}
public long getNext() {
return next.toLong();
}
@ -48,7 +62,7 @@ public class ForkId {
}
public List<Bytes> getForkIdAsBytesList() {
List<Bytes> bytesList = new ArrayList<>();
final List<Bytes> bytesList = new ArrayList<>();
bytesList.add(hash);
bytesList.add(next);
@ -99,6 +113,6 @@ public class ForkId {
@Override
public int hashCode() {
return super.hashCode();
return 31 * this.hash.hashCode() * this.next.hashCode();
}
}

@ -12,7 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.eth.manager;
package org.hyperledger.besu.ethereum.forkid;
import static com.google.common.base.Preconditions.checkNotNull;
@ -78,7 +78,7 @@ public class ForkIdManager {
}
@VisibleForTesting
List<ForkId> getForkIds() {
public List<ForkId> getForkIds() {
return this.forkIds;
}
@ -96,7 +96,7 @@ public class ForkIdManager {
* @param forkId to be validated.
* @return boolean (peer valid (true) or invalid (false))
*/
boolean peerCheck(final ForkId forkId) {
public boolean peerCheck(final ForkId forkId) {
if (forkId == null || onlyZerosForkBlocks) {
return true; // Another method must be used to validate (i.e. genesis hash)
}

@ -89,16 +89,16 @@ public class EthPeers {
this.maxPeers = maxPeers;
this.maxMessageSize = maxMessageSize;
this.bestPeerComparator = HEAVIEST_CHAIN;
metricsSystem.createIntegerGauge(
BesuMetricCategory.PEERS,
"pending_peer_requests_current",
"Number of peer requests currently pending because peers are busy",
pendingRequests::size);
metricsSystem.createIntegerGauge(
BesuMetricCategory.ETHEREUM,
"peer_count",
"The current number of peers connected",
() -> (int) streamAvailablePeers().count());
metricsSystem.createIntegerGauge(
BesuMetricCategory.PEERS,
"pending_peer_requests_current",
"Number of peer requests currently pending because peers are busy",
pendingRequests::size);
}
public void registerConnection(
@ -112,11 +112,8 @@ public class EthPeers {
maxMessageSize,
clock,
permissioningProviders);
final EthPeer ethPeer = connections.putIfAbsent(peerConnection, peer);
LOG.debug(
"Adding new EthPeer {} {}",
peer.getShortNodeId(),
ethPeer == null ? "for the first time" : "");
connections.putIfAbsent(peerConnection, peer);
LOG.debug("Adding new EthPeer {}", peer.nodeId());
}
public void registerDisconnect(final PeerConnection connection) {

@ -31,6 +31,8 @@ import org.hyperledger.besu.ethereum.eth.sync.BlockBroadcaster;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.forkid.ForkId;
import org.hyperledger.besu.ethereum.forkid.ForkIdManager;
import org.hyperledger.besu.ethereum.p2p.network.ProtocolManager;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.PeerConnection;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.PeerConnection.PeerNotConnected;

@ -16,7 +16,7 @@ package org.hyperledger.besu.ethereum.eth.messages;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.eth.manager.ForkId;
import org.hyperledger.besu.ethereum.forkid.ForkId;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.AbstractMessageData;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;

@ -65,7 +65,7 @@ public class PeerValidatorRunner {
}
protected void scheduleNextCheck(final EthPeer ethPeer) {
Duration timeout = peerValidator.nextValidationCheckTimeout(ethPeer);
final Duration timeout = peerValidator.nextValidationCheckTimeout(ethPeer);
ethContext.getScheduler().scheduleFutureTask(() -> checkPeer(ethPeer), timeout);
}
}

@ -125,7 +125,7 @@ public class PivotSelectorFromPeers implements PivotBlockSelector {
}
private long conservativelyEstimatedPivotBlock() {
long estimatedNextPivot =
final long estimatedNextPivot =
syncState.getLocalChainHeight() + syncConfig.getFastSyncPivotDistance();
return Math.min(syncState.bestChainHeight(), estimatedNextPivot);
}

@ -18,8 +18,8 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.eth.ForkIdTestUtil.GenesisHash;
import static org.hyperledger.besu.ethereum.eth.ForkIdTestUtil.mockBlockchain;
import org.hyperledger.besu.ethereum.eth.manager.ForkId;
import org.hyperledger.besu.ethereum.eth.manager.ForkIdManager;
import org.hyperledger.besu.ethereum.forkid.ForkId;
import org.hyperledger.besu.ethereum.forkid.ForkIdManager;
import java.util.Arrays;
import java.util.Collection;

@ -21,7 +21,7 @@ import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.ForkId;
import org.hyperledger.besu.ethereum.forkid.ForkId;
import java.util.Arrays;
import java.util.List;

@ -16,7 +16,7 @@ package org.hyperledger.besu.ethereum.eth;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.eth.manager.ForkId;
import org.hyperledger.besu.ethereum.forkid.ForkId;
import org.hyperledger.besu.ethereum.rlp.RLPInput;
import java.util.ArrayList;

@ -25,6 +25,8 @@ import org.hyperledger.besu.ethereum.eth.ForkIdTestUtil.ForkIds;
import org.hyperledger.besu.ethereum.eth.ForkIdTestUtil.GenesisHash;
import org.hyperledger.besu.ethereum.eth.ForkIdTestUtil.Network;
import org.hyperledger.besu.ethereum.eth.ForkIdTestUtil.PeerCheckCase;
import org.hyperledger.besu.ethereum.forkid.ForkId;
import org.hyperledger.besu.ethereum.forkid.ForkIdManager;
import java.util.Arrays;
import java.util.Collection;

@ -64,6 +64,7 @@ import org.hyperledger.besu.ethereum.eth.sync.state.SyncState;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolFactory;
import org.hyperledger.besu.ethereum.forkid.ForkIdManager;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.PeerConnection;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability;

@ -31,6 +31,7 @@ import org.hyperledger.besu.ethereum.eth.manager.DeterministicEthScheduler.Timeo
import org.hyperledger.besu.ethereum.eth.peervalidation.PeerValidator;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.forkid.ForkIdManager;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.DefaultMessage;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData;

@ -19,7 +19,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.eth.EthProtocolVersion;
import org.hyperledger.besu.ethereum.eth.manager.ForkId;
import org.hyperledger.besu.ethereum.forkid.ForkId;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData;
import java.math.BigInteger;

@ -179,7 +179,8 @@ public class TestNode implements Closeable {
.metricsSystem(new NoOpMetricsSystem())
.supportedCapabilities(capabilities)
.storageProvider(new InMemoryKeyValueStorageProvider())
.forkIdSupplier(() -> Collections.singletonList(Bytes.EMPTY))
.blockchain(blockchain)
.forks(Collections.emptyList())
.build())
.metricsSystem(new NoOpMetricsSystem())
.build();

@ -37,11 +37,11 @@ import org.hyperledger.besu.ethereum.eth.manager.EthMessages;
import org.hyperledger.besu.ethereum.eth.manager.EthPeers;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager;
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
import org.hyperledger.besu.ethereum.eth.manager.ForkIdManager;
import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.sync.state.SyncState;
import org.hyperledger.besu.ethereum.eth.transactions.sorter.GasPricePendingTransactionsSorter;
import org.hyperledger.besu.ethereum.forkid.ForkIdManager;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;

@ -32,6 +32,7 @@ public class DiscoveryConfiguration {
private List<EnodeURL> bootnodes = new ArrayList<>();
private String dnsDiscoveryURL;
private boolean discoveryV5Enabled = false;
private boolean filterOnEnrForkId = false;
public static DiscoveryConfiguration create() {
return new DiscoveryConfiguration();
@ -114,12 +115,20 @@ public class DiscoveryConfiguration {
return this;
}
public void setDiscoveryV5Enabled(final boolean discoveryV5Enabled) {
this.discoveryV5Enabled = discoveryV5Enabled;
}
public boolean isDiscoveryV5Enabled() {
return discoveryV5Enabled;
}
public void setDiscoveryV5Enabled(final boolean discoveryV5Enabled) {
this.discoveryV5Enabled = discoveryV5Enabled;
public void setFilterOnEnrForkId(final boolean filterOnEnrForkId) {
this.filterOnEnrForkId = filterOnEnrForkId;
}
public boolean isFilterOnEnrForkIdEnabled() {
return filterOnEnrForkId;
}
@Override
@ -165,6 +174,10 @@ public class DiscoveryConfiguration {
+ bootnodes
+ ", dnsDiscoveryURL="
+ dnsDiscoveryURL
+ ", isDiscoveryV5Enabled="
+ discoveryV5Enabled
+ ", isFilterOnEnrForkIdEnabled="
+ filterOnEnrForkId
+ '}';
}
}

@ -14,6 +14,7 @@
*/
package org.hyperledger.besu.ethereum.p2p.discovery;
import org.hyperledger.besu.ethereum.forkid.ForkId;
import org.hyperledger.besu.ethereum.p2p.peers.DefaultPeer;
import org.hyperledger.besu.ethereum.p2p.peers.Peer;
import org.hyperledger.besu.ethereum.p2p.peers.PeerId;
@ -42,6 +43,7 @@ public class DiscoveryPeer extends DefaultPeer {
private long lastAttemptedConnection = 0;
private NodeRecord nodeRecord;
private Optional<ForkId> forkId = Optional.empty();
private DiscoveryPeer(final EnodeURL enode, final Endpoint endpoint) {
super(enode);
@ -136,6 +138,11 @@ public class DiscoveryPeer extends DefaultPeer {
public void setNodeRecord(final NodeRecord nodeRecord) {
this.nodeRecord = nodeRecord;
this.forkId = ForkId.fromRawForkId(nodeRecord.get("eth"));
}
public Optional<ForkId> getForkId() {
return this.forkId;
}
public boolean discoveryEndpointMatches(final DiscoveryPeer peer) {

@ -21,10 +21,10 @@ import org.hyperledger.besu.crypto.Hash;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.ethereum.forkid.ForkIdManager;
import org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration;
import org.hyperledger.besu.ethereum.p2p.discovery.internal.Packet;
import org.hyperledger.besu.ethereum.p2p.discovery.internal.PeerDiscoveryController;
import org.hyperledger.besu.ethereum.p2p.discovery.internal.PeerDiscoveryController.AsyncExecutor;
import org.hyperledger.besu.ethereum.p2p.discovery.internal.PeerRequirement;
import org.hyperledger.besu.ethereum.p2p.discovery.internal.PingPacketData;
import org.hyperledger.besu.ethereum.p2p.discovery.internal.TimerUtil;
@ -84,6 +84,8 @@ public abstract class PeerDiscoveryAgent {
private final NatService natService;
private final MetricsSystem metricsSystem;
private final RlpxAgent rlpxAgent;
private final ForkIdManager forkIdManager;
/* The peer controller, which takes care of the state machine of peers. */
protected Optional<PeerDiscoveryController> controller = Optional.empty();
@ -110,7 +112,7 @@ public abstract class PeerDiscoveryAgent {
final NatService natService,
final MetricsSystem metricsSystem,
final StorageProvider storageProvider,
final Supplier<List<Bytes>> forkIdSupplier,
final ForkIdManager forkIdManager,
final RlpxAgent rlpxAgent) {
this.metricsSystem = metricsSystem;
checkArgument(nodeKey != null, "nodeKey cannot be null");
@ -129,13 +131,14 @@ public abstract class PeerDiscoveryAgent {
this.id = nodeKey.getPublicKey().getEncodedBytes();
this.storageProvider = storageProvider;
this.forkIdSupplier = forkIdSupplier;
this.forkIdManager = forkIdManager;
this.forkIdSupplier = () -> forkIdManager.getForkIdForChainHead().getForkIdAsBytesList();
this.rlpxAgent = rlpxAgent;
}
protected abstract TimerUtil createTimer();
protected abstract AsyncExecutor createWorkerExecutor();
protected abstract PeerDiscoveryController.AsyncExecutor createWorkerExecutor();
protected abstract CompletableFuture<InetSocketAddress> listenForConnections();
@ -250,6 +253,10 @@ public abstract class PeerDiscoveryAgent {
this.peerRequirements.add(peerRequirement);
}
public boolean checkForkId(final DiscoveryPeer peer) {
return peer.getForkId().map(forkIdManager::peerCheck).orElse(true);
}
private void startController(final DiscoveryPeer localNode) {
final PeerDiscoveryController controller = createController(localNode);
this.controller = Optional.of(controller);
@ -267,6 +274,8 @@ public abstract class PeerDiscoveryAgent {
.peerRequirement(PeerRequirement.combine(peerRequirements))
.peerPermissions(peerPermissions)
.metricsSystem(metricsSystem)
.forkIdManager(forkIdManager)
.filterOnEnrForkId((config.isFilterOnEnrForkIdEnabled()))
.rlpxAgent(rlpxAgent)
.build();
}

@ -33,7 +33,10 @@ public enum PeerDiscoveryStatus {
* We have successfully bonded with this {@link DiscoveryPeer}, and we are able to exchange
* messages with them.
*/
BONDED;
BONDED,
/** We have requested the ENR record from this {@link DiscoveryPeer} */
ENR_REQUESTED;
@Override
public String toString() {

@ -20,6 +20,7 @@ import static org.hyperledger.besu.util.Slf4jLambdaHelper.debugLambda;
import static org.hyperledger.besu.util.Slf4jLambdaHelper.traceLambda;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.ethereum.forkid.ForkIdManager;
import org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration;
import org.hyperledger.besu.ethereum.p2p.discovery.internal.Packet;
import org.hyperledger.besu.ethereum.p2p.discovery.internal.PeerDiscoveryController;
@ -39,7 +40,6 @@ import java.net.BindException;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.nio.channels.UnsupportedAddressTypeException;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.IntSupplier;
@ -55,7 +55,6 @@ import io.vertx.core.Vertx;
import io.vertx.core.datagram.DatagramPacket;
import io.vertx.core.datagram.DatagramSocket;
import io.vertx.core.datagram.DatagramSocketOptions;
import org.apache.tuweni.bytes.Bytes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -74,7 +73,7 @@ public class VertxPeerDiscoveryAgent extends PeerDiscoveryAgent {
final NatService natService,
final MetricsSystem metricsSystem,
final StorageProvider storageProvider,
final Supplier<List<Bytes>> forkIdSupplier,
final ForkIdManager forkIdManager,
final RlpxAgent rlpxAgent) {
super(
nodeKey,
@ -83,7 +82,7 @@ public class VertxPeerDiscoveryAgent extends PeerDiscoveryAgent {
natService,
metricsSystem,
storageProvider,
forkIdSupplier,
forkIdManager,
rlpxAgent);
checkArgument(vertx != null, "vertx instance cannot be null");
this.vertx = vertx;

@ -21,6 +21,8 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.ethereum.forkid.ForkId;
import org.hyperledger.besu.ethereum.forkid.ForkIdManager;
import org.hyperledger.besu.ethereum.p2p.discovery.DiscoveryPeer;
import org.hyperledger.besu.ethereum.p2p.discovery.PeerDiscoveryStatus;
import org.hyperledger.besu.ethereum.p2p.peers.Peer;
@ -114,7 +116,8 @@ public class PeerDiscoveryController {
private final Collection<DiscoveryPeer> bootstrapNodes;
/* A tracker for inflight interactions and the state machine of a peer. */
private final Map<Bytes, PeerInteractionState> inflightInteractions = new ConcurrentHashMap<>();
private final Map<Bytes, Map<PacketType, PeerInteractionState>> inflightInteractions =
new ConcurrentHashMap<>();
private final AtomicBoolean started = new AtomicBoolean(false);
@ -126,6 +129,8 @@ public class PeerDiscoveryController {
private final DiscoveryProtocolLogger discoveryProtocolLogger;
private final LabelledMetric<Counter> interactionCounter;
private final LabelledMetric<Counter> interactionRetryCounter;
private final ForkIdManager forkIdManager;
private final boolean filterOnEnrForkId;
private final RlpxAgent rlpxAgent;
private RetryDelayFunction retryDelayFunction = RetryDelayFunction.linear(1.5, 2000, 60000);
@ -156,6 +161,8 @@ public class PeerDiscoveryController {
final PeerPermissions peerPermissions,
final MetricsSystem metricsSystem,
final Optional<Cache<Bytes, Packet>> maybeCacheForEnrRequests,
final ForkIdManager forkIdManager,
final boolean filterOnEnrForkId,
final RlpxAgent rlpxAgent) {
this.timerUtil = timerUtil;
this.nodeKey = nodeKey;
@ -168,7 +175,6 @@ public class PeerDiscoveryController {
this.peerRequirement = peerRequirement;
this.outboundMessageHandler = outboundMessageHandler;
this.discoveryProtocolLogger = new DiscoveryProtocolLogger(metricsSystem);
this.peerPermissions = new PeerDiscoveryPermissions(localPeer, peerPermissions);
this.rlpxAgent = rlpxAgent;
@ -178,14 +184,14 @@ public class PeerDiscoveryController {
"Current number of inflight discovery interactions",
inflightInteractions::size);
interactionCounter =
this.interactionCounter =
metricsSystem.createLabelledCounter(
BesuMetricCategory.NETWORK,
"discovery_interaction_count",
"Total number of discovery interactions initiated",
"type");
interactionRetryCounter =
this.interactionRetryCounter =
metricsSystem.createLabelledCounter(
BesuMetricCategory.NETWORK,
"discovery_interaction_retry_count",
@ -194,6 +200,9 @@ public class PeerDiscoveryController {
this.cachedEnrRequests =
maybeCacheForEnrRequests.orElse(
CacheBuilder.newBuilder().maximumSize(50).expireAfterWrite(10, SECONDS).build());
this.forkIdManager = forkIdManager;
this.filterOnEnrForkId = filterOnEnrForkId;
}
public static Builder builder() {
@ -205,6 +214,7 @@ public class PeerDiscoveryController {
throw new IllegalStateException("The peer table had already been started");
}
LOG.debug("Starting with filterOnEnrForkId = {}", filterOnEnrForkId);
final List<DiscoveryPeer> initialDiscoveryPeers =
bootstrapNodes.stream()
.filter(peerPermissions::isAllowedInPeerTable)
@ -246,7 +256,13 @@ public class PeerDiscoveryController {
tableRefreshTimerId = OptionalLong.empty();
cleanTableTimerId.ifPresent(timerUtil::cancelTimer);
cleanTableTimerId = OptionalLong.empty();
inflightInteractions.values().forEach(PeerInteractionState::cancelTimers);
inflightInteractions
.values()
.forEach(
l -> {
l.values().forEach(s -> s.cancelTimers());
l.clear();
});
inflightInteractions.clear();
return CompletableFuture.completedFuture(null);
}
@ -314,6 +330,9 @@ public class PeerDiscoveryController {
matchInteraction(packet)
.ifPresent(
interaction -> {
if (filterOnEnrForkId) {
requestENR(peer);
}
bondingPeers.invalidate(peer.getId());
addToPeerTable(peer);
recursivePeerRefreshState.onBondingComplete(peer);
@ -350,13 +369,34 @@ public class PeerDiscoveryController {
}
break;
case ENR_RESPONSE:
// Currently there is no use case where an ENRResponse will be sent otherwise
// logic can be added here to query and store the response ENRs
packet
.getPacketData(ENRResponsePacketData.class)
.filter(p -> p.getEnr().getNodeId().equals(sender.getId()))
.ifPresent(p -> LOG.debug("Received NodeRecord: {}", p.getEnr().asEnr()));
matchInteraction(packet)
.ifPresent(
interaction -> {
final Optional<ENRResponsePacketData> packetData =
packet.getPacketData(ENRResponsePacketData.class);
final NodeRecord enr = packetData.get().getEnr();
peer.setNodeRecord(enr);
final Optional<ForkId> maybeForkId = peer.getForkId();
if (maybeForkId.isPresent()) {
if (forkIdManager.peerCheck(maybeForkId.get())) {
connectOnRlpxLayer(peer);
LOG.debug(
"Peer {} PASSED fork id check. ForkId received: {}",
sender.getId(),
maybeForkId.get());
} else {
LOG.debug(
"Peer {} FAILED fork id check. ForkId received: {}",
sender.getId(),
maybeForkId.get());
}
} else {
// if the peer hasn't sent the ForkId try to connect to it anyways
connectOnRlpxLayer(peer);
LOG.debug("No fork id sent by peer: {}", peer.getId());
}
});
break;
}
}
@ -391,7 +431,9 @@ public class PeerDiscoveryController {
if (peer.getStatus() != PeerDiscoveryStatus.BONDED) {
peer.setStatus(PeerDiscoveryStatus.BONDED);
connectOnRlpxLayer(peer);
if (!filterOnEnrForkId) {
connectOnRlpxLayer(peer);
}
}
final PeerTable.AddResult result = peerTable.tryAdd(peer);
@ -408,17 +450,26 @@ public class PeerDiscoveryController {
return true;
}
private void connectOnRlpxLayer(final DiscoveryPeer peer) {
void connectOnRlpxLayer(final DiscoveryPeer peer) {
rlpxAgent.connect(peer);
}
private Optional<PeerInteractionState> matchInteraction(final Packet packet) {
final PeerInteractionState interaction = inflightInteractions.get(packet.getNodeId());
final Bytes nodeId = packet.getNodeId();
final Map<PacketType, PeerInteractionState> stateMap = inflightInteractions.get(nodeId);
if (stateMap == null) {
return Optional.empty();
}
final PacketType packetType = packet.getType();
final PeerInteractionState interaction = stateMap.get(packetType);
if (interaction == null || !interaction.test(packet)) {
return Optional.empty();
}
interaction.cancelTimers();
inflightInteractions.remove(packet.getNodeId());
stateMap.remove(packetType);
if (stateMap.isEmpty()) {
inflightInteractions.remove(nodeId);
}
return Optional.of(interaction);
}
@ -498,7 +549,44 @@ public class PeerDiscoveryController {
// The filter condition will be updated as soon as the action is performed.
final PeerInteractionState peerInteractionState =
new PeerInteractionState(action, peer.getId(), PacketType.PONG, packet -> false, true);
new PeerInteractionState(action, peer.getId(), PacketType.PONG, packet -> false);
dispatchInteraction(peer, peerInteractionState);
}
/**
* Initiates an enr request cycle with a peer.
*
* @param peer The targeted peer.
*/
@VisibleForTesting
void requestENR(final DiscoveryPeer peer) {
peer.setStatus(PeerDiscoveryStatus.ENR_REQUESTED);
final Consumer<PeerInteractionState> action =
interaction -> {
final ENRRequestPacketData data = ENRRequestPacketData.create();
createPacket(
PacketType.ENR_REQUEST,
data,
enrPacket -> {
final Bytes enrHash = enrPacket.getHash();
// Update the matching filter to only accept the ENRResponse if it echoes the hash
// of our request.
final Predicate<Packet> newFilter =
packet ->
packet
.getPacketData(ENRResponsePacketData.class)
.map(enr -> enr.getRequestHash().equals(enrHash))
.orElse(false);
interaction.updateFilter(newFilter);
sendPacket(peer, enrPacket);
});
};
// The filter condition will be updated as soon as the action is performed.
final PeerInteractionState peerInteractionState =
new PeerInteractionState(action, peer.getId(), PacketType.ENR_RESPONSE, packet -> false);
dispatchInteraction(peer, peerInteractionState);
}
@ -544,7 +632,7 @@ public class PeerDiscoveryController {
sendPacket(peer, PacketType.FIND_NEIGHBORS, data);
};
final PeerInteractionState interaction =
new PeerInteractionState(action, peer.getId(), PacketType.NEIGHBORS, packet -> true, true);
new PeerInteractionState(action, peer.getId(), PacketType.NEIGHBORS, packet -> true);
dispatchInteraction(peer, interaction);
}
@ -558,11 +646,15 @@ public class PeerDiscoveryController {
* @param state The state.
*/
private void dispatchInteraction(final Peer peer, final PeerInteractionState state) {
final PeerInteractionState previous = inflightInteractions.put(peer.getId(), state);
final Bytes id = peer.getId();
final PeerInteractionState previous =
inflightInteractions
.computeIfAbsent(id, k -> new ConcurrentHashMap<>())
.put(state.expectedType, state);
if (previous != null) {
previous.cancelTimers();
}
state.execute(0, 0);
state.execute();
}
private void respondToPing(
@ -662,22 +754,21 @@ public class PeerDiscoveryController {
private final Counter retryCounter;
/** A custom filter to accept transitions out of this state. */
private Predicate<Packet> filter;
/** Whether the action associated to this state is retryable or not. */
private final boolean retryable;
/** Timers associated with this entry. */
private OptionalLong timerId = OptionalLong.empty();
private long delay = 0;
private int retryCount = 0;
PeerInteractionState(
final Consumer<PeerInteractionState> action,
final Bytes peerId,
final PacketType expectedType,
final Predicate<Packet> filter,
final boolean retryable) {
final Predicate<Packet> filter) {
this.action = action;
this.peerId = peerId;
this.expectedType = expectedType;
this.filter = filter;
this.retryable = retryable;
interactionCounter.labels(expectedType.name()).inc();
retryCounter = interactionRetryCounter.labels(expectedType.name());
}
@ -691,27 +782,27 @@ public class PeerDiscoveryController {
this.filter = filter;
}
/**
* Executes the action associated with this state. Sets a "boomerang" timer to itself in case
* the action is retryable.
*
* @param lastTimeout the previous timeout, or 0 if this is the first time the action is being
* executed.
*/
void execute(final long lastTimeout, final int retryCount) {
/** Executes the action associated with this state. Sets a "boomerang" timer to itself. */
void execute() {
action.accept(this);
if (retryable && retryCount < MAX_RETRIES) {
final long newTimeout = retryDelayFunction.apply(lastTimeout);
if (retryCount < MAX_RETRIES) {
this.delay = retryDelayFunction.apply(this.delay);
timerId =
OptionalLong.of(
timerUtil.setTimer(
newTimeout,
this.delay,
() -> {
retryCounter.inc();
execute(newTimeout, retryCount + 1);
retryCount++;
execute();
}));
} else {
inflightInteractions.remove(peerId);
final Map<PacketType, PeerInteractionState> peerInteractionStateMap =
inflightInteractions.get(peerId);
peerInteractionStateMap.remove(expectedType);
if (peerInteractionStateMap.isEmpty()) {
inflightInteractions.remove(peerId);
}
}
}
@ -741,9 +832,11 @@ public class PeerDiscoveryController {
private TimerUtil timerUtil;
private AsyncExecutor workerExecutor;
private MetricsSystem metricsSystem;
private boolean filterOnEnrForkId;
private Cache<Bytes, Packet> cachedEnrRequests =
CacheBuilder.newBuilder().maximumSize(50).expireAfterWrite(10, SECONDS).build();
private ForkIdManager forkIdManager;
private RlpxAgent rlpxAgent;
private Builder() {}
@ -769,6 +862,8 @@ public class PeerDiscoveryController {
peerPermissions,
metricsSystem,
Optional.of(cachedEnrRequests),
forkIdManager,
filterOnEnrForkId,
rlpxAgent);
}
@ -778,6 +873,7 @@ public class PeerDiscoveryController {
validateRequiredDependency(timerUtil, "TimerUtil");
validateRequiredDependency(workerExecutor, "AsyncExecutor");
validateRequiredDependency(metricsSystem, "MetricsSystem");
validateRequiredDependency(forkIdManager, "ForkIdManager");
validateRequiredDependency(rlpxAgent, "RlpxAgent");
}
@ -856,6 +952,11 @@ public class PeerDiscoveryController {
return this;
}
public Builder filterOnEnrForkId(final boolean filterOnEnrForkId) {
this.filterOnEnrForkId = filterOnEnrForkId;
return this;
}
public Builder cacheForEnrRequests(final Cache<Bytes, Packet> cacheToUse) {
checkNotNull(cacheToUse);
this.cachedEnrRequests = cacheToUse;
@ -867,5 +968,11 @@ public class PeerDiscoveryController {
this.rlpxAgent = rlpxAgent;
return this;
}
public Builder forkIdManager(final ForkIdManager forkIdManager) {
checkNotNull(forkIdManager);
this.forkIdManager = forkIdManager;
return this;
}
}
}

@ -18,7 +18,10 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.Util;
import org.hyperledger.besu.ethereum.forkid.ForkIdManager;
import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration;
import org.hyperledger.besu.ethereum.p2p.discovery.DiscoveryPeer;
import org.hyperledger.besu.ethereum.p2p.discovery.PeerDiscoveryAgent;
@ -65,7 +68,6 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -140,7 +142,7 @@ public class DefaultP2PNetwork implements P2PNetwork {
private final AtomicBoolean started = new AtomicBoolean(false);
private final AtomicBoolean stopped = new AtomicBoolean(false);
private final CountDownLatch shutdownLatch = new CountDownLatch(2);
private final Duration shutdownTimeout = Duration.ofMinutes(1);
private final Duration shutdownTimeout = Duration.ofSeconds(15);
private DNSDaemon dnsDaemon;
/**
@ -368,6 +370,7 @@ public class DefaultP2PNetwork implements P2PNetwork {
rlpxAgent.connect(
streamDiscoveredPeers()
.filter(peer -> peer.getStatus() == PeerDiscoveryStatus.BONDED)
.filter(peerDiscoveryAgent::checkForkId)
.sorted(Comparator.comparing(DiscoveryPeer::getLastAttemptedConnection)));
}
@ -475,8 +478,10 @@ public class DefaultP2PNetwork implements P2PNetwork {
private MetricsSystem metricsSystem;
private StorageProvider storageProvider;
private Supplier<List<Bytes>> forkIdSupplier;
private Optional<TLSConfiguration> p2pTLSConfiguration = Optional.empty();
private Blockchain blockchain;
private List<Long> forks;
private boolean legacyForkIdEnabled = false;
public P2PNetwork build() {
validate();
@ -518,10 +523,11 @@ public class DefaultP2PNetwork implements P2PNetwork {
checkState(metricsSystem != null, "MetricsSystem must be set.");
checkState(storageProvider != null, "StorageProvider must be set.");
checkState(peerDiscoveryAgent != null || vertx != null, "Vertx must be set.");
checkState(forkIdSupplier != null, "ForkIdSupplier must be set.");
}
private PeerDiscoveryAgent createDiscoveryAgent() {
final ForkIdManager forkIdManager =
new ForkIdManager(blockchain, forks, this.legacyForkIdEnabled);
return new VertxPeerDiscoveryAgent(
vertx,
@ -531,7 +537,7 @@ public class DefaultP2PNetwork implements P2PNetwork {
natService,
metricsSystem,
storageProvider,
forkIdSupplier,
forkIdManager,
rlpxAgent);
}
@ -625,16 +631,27 @@ public class DefaultP2PNetwork implements P2PNetwork {
return this;
}
public Builder forkIdSupplier(final Supplier<List<Bytes>> forkIdSupplier) {
checkNotNull(forkIdSupplier);
this.forkIdSupplier = forkIdSupplier;
return this;
}
public Builder p2pTLSConfiguration(final Optional<TLSConfiguration> p2pTLSConfiguration) {
checkNotNull(p2pTLSConfiguration);
this.p2pTLSConfiguration = p2pTLSConfiguration;
return this;
}
public Builder blockchain(final MutableBlockchain blockchain) {
checkNotNull(blockchain);
this.blockchain = blockchain;
return this;
}
public Builder forks(final List<Long> forks) {
checkNotNull(forks);
this.forks = forks;
return this;
}
public Builder legacyForkIdEnabled(final boolean legacyForkIdEnabled) {
this.legacyForkIdEnabled = legacyForkIdEnabled;
return this;
}
}
}

@ -28,6 +28,7 @@ import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.crypto.NodeKeyUtils;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.ethereum.forkid.ForkId;
import org.hyperledger.besu.ethereum.p2p.discovery.PeerDiscoveryTestHelper.AgentBuilder;
import org.hyperledger.besu.ethereum.p2p.discovery.internal.FindNeighborsPacketData;
import org.hyperledger.besu.ethereum.p2p.discovery.internal.MockPeerDiscoveryAgent;
@ -106,12 +107,11 @@ public class PeerDiscoveryAgentTest {
assertThat(nodeRecord.getSeq()).isNotNull();
assertThat(nodeRecord.get("eth")).isNotNull();
assertThat(nodeRecord.get("eth"))
.isEqualTo(Collections.singletonList(Collections.singletonList(Bytes.EMPTY)));
.isEqualTo(
Collections.singletonList(new ForkId(Bytes.EMPTY, Bytes.EMPTY).getForkIdAsBytesList()));
assertThat(nodeRecord.asEnr())
.isEqualTo(
"enr:-JC4QOfroMOa1sB6ajxcBKdWn3s9S4Ojl33pbRm72S5FnCwyZfskmjkJvZznQaWNTrOHrnKxw1R9xMm9rl"
+ "EGOcsOyscBg2V0aMLBgIJpZIJ2NIJpcIR_AAABiXNlY3AyNTZrMaEDymNMrg1JrLQB2KTGtv6MVbcNEV"
+ "v0AHacwUAPMljNMTiDdGNwAoN1ZHCCdl8");
"enr:-JG4QF0FFhEXDu_G-1LD5lkWh5-cbnw8vJ00NvO8vGnAf85JMwLiP-Qo49DL2xYMzX3zg_d5VXhegmoVTFJRWgZAtCYBg2V0aMPCgICCaWSCdjSCaXCEfwAAAYlzZWNwMjU2azGhA8pjTK4NSay0Adikxrb-jFW3DRFb9AB2nMFADzJYzTE4g3RjcAKDdWRwgnZf");
}
@Test

@ -17,10 +17,13 @@ package org.hyperledger.besu.ethereum.p2p.discovery;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.Arrays.asList;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.crypto.NodeKeyUtils;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.forkid.ForkId;
import org.hyperledger.besu.ethereum.forkid.ForkIdManager;
import org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration;
import org.hyperledger.besu.ethereum.p2p.discovery.internal.MockPeerDiscoveryAgent;
import org.hyperledger.besu.ethereum.p2p.discovery.internal.Packet;
@ -285,6 +288,10 @@ public class PeerDiscoveryTestHelper {
config.setBindPort(port);
config.setActive(active);
final ForkIdManager mockForkIdManager = mock(ForkIdManager.class);
final ForkId forkId = new ForkId(Bytes.EMPTY, Bytes.EMPTY);
when(mockForkIdManager.getForkIdForChainHead()).thenReturn(forkId);
when(mockForkIdManager.peerCheck(forkId)).thenReturn(true);
final MockPeerDiscoveryAgent mockPeerDiscoveryAgent =
new MockPeerDiscoveryAgent(
nodeKey,
@ -292,7 +299,7 @@ public class PeerDiscoveryTestHelper {
peerPermissions,
agents,
natService,
() -> Collections.singletonList(Bytes.EMPTY),
mockForkIdManager,
mock(RlpxAgent.class));
mockPeerDiscoveryAgent.getAdvertisedPeer().ifPresent(peer -> peer.setNodeRecord(nodeRecord));

@ -18,10 +18,10 @@ import static org.apache.tuweni.bytes.Bytes.wrapBuffer;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider;
import org.hyperledger.besu.ethereum.forkid.ForkIdManager;
import org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration;
import org.hyperledger.besu.ethereum.p2p.discovery.DiscoveryPeer;
import org.hyperledger.besu.ethereum.p2p.discovery.PeerDiscoveryAgent;
import org.hyperledger.besu.ethereum.p2p.discovery.internal.PeerDiscoveryController.AsyncExecutor;
import org.hyperledger.besu.ethereum.p2p.permissions.PeerPermissions;
import org.hyperledger.besu.ethereum.p2p.rlpx.RlpxAgent;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
@ -34,7 +34,6 @@ import java.util.Deque;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;
import org.apache.tuweni.bytes.Bytes;
import org.slf4j.Logger;
@ -54,7 +53,7 @@ public class MockPeerDiscoveryAgent extends PeerDiscoveryAgent {
final PeerPermissions peerPermissions,
final Map<Bytes, MockPeerDiscoveryAgent> agentNetwork,
final NatService natService,
final Supplier<List<Bytes>> forkIdSupplier,
final ForkIdManager forkIdManager,
final RlpxAgent rlpxAgent) {
super(
nodeKey,
@ -63,7 +62,7 @@ public class MockPeerDiscoveryAgent extends PeerDiscoveryAgent {
natService,
new NoOpMetricsSystem(),
new InMemoryKeyValueStorageProvider(),
forkIdSupplier,
forkIdManager,
rlpxAgent);
this.agentNetwork = agentNetwork;
}
@ -82,7 +81,8 @@ public class MockPeerDiscoveryAgent extends PeerDiscoveryAgent {
* @return A list of packets received by this agent
*/
public List<IncomingPacket> getIncomingPackets() {
List<IncomingPacket> packets = Arrays.asList(incomingPackets.toArray(new IncomingPacket[0]));
final List<IncomingPacket> packets =
Arrays.asList(incomingPackets.toArray(new IncomingPacket[0]));
incomingPackets.clear();
return packets;
}
@ -91,19 +91,20 @@ public class MockPeerDiscoveryAgent extends PeerDiscoveryAgent {
protected CompletableFuture<InetSocketAddress> listenForConnections() {
isRunning = true;
// Skip network setup for tests
InetSocketAddress address = new InetSocketAddress(config.getBindHost(), config.getBindPort());
final InetSocketAddress address =
new InetSocketAddress(config.getBindHost(), config.getBindPort());
return CompletableFuture.completedFuture(address);
}
@Override
protected CompletableFuture<Void> sendOutgoingPacket(
final DiscoveryPeer toPeer, final Packet packet) {
CompletableFuture<Void> result = new CompletableFuture<>();
final CompletableFuture<Void> result = new CompletableFuture<>();
if (!this.isRunning) {
result.completeExceptionally(new Exception("Attempt to send message from an inactive agent"));
}
MockPeerDiscoveryAgent toAgent = agentNetwork.get(toPeer.getId());
final MockPeerDiscoveryAgent toAgent = agentNetwork.get(toPeer.getId());
if (toAgent == null) {
result.completeExceptionally(
new Exception(
@ -137,7 +138,7 @@ public class MockPeerDiscoveryAgent extends PeerDiscoveryAgent {
}
@Override
protected AsyncExecutor createWorkerExecutor() {
protected PeerDiscoveryController.AsyncExecutor createWorkerExecutor() {
return new BlockingAsyncExecutor();
}

@ -31,7 +31,12 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.crypto.Hash;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.ethereum.forkid.ForkId;
import org.hyperledger.besu.ethereum.forkid.ForkIdManager;
import org.hyperledger.besu.ethereum.p2p.discovery.DiscoveryPeer;
import org.hyperledger.besu.ethereum.p2p.discovery.Endpoint;
import org.hyperledger.besu.ethereum.p2p.discovery.PeerDiscoveryStatus;
@ -49,6 +54,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
@ -59,14 +65,19 @@ import java.util.stream.Collectors;
import com.google.common.base.Ticker;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.net.InetAddresses;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.bytes.MutableBytes;
import org.apache.tuweni.units.bigints.UInt256;
import org.apache.tuweni.units.bigints.UInt64;
import org.assertj.core.api.Assertions;
import org.ethereum.beacon.discovery.schema.EnrField;
import org.ethereum.beacon.discovery.schema.IdentitySchema;
import org.ethereum.beacon.discovery.schema.IdentitySchemaInterpreter;
import org.ethereum.beacon.discovery.schema.NodeRecord;
import org.ethereum.beacon.discovery.schema.NodeRecordFactory;
import org.jetbrains.annotations.NotNull;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@ -1468,6 +1479,175 @@ public class PeerDiscoveryControllerTest {
matchPacketOfType(PacketType.ENR_RESPONSE));
}
@Test
public void shouldFiltersOnForkIdSuccess() {
final List<NodeKey> nodeKeys = PeerDiscoveryTestHelper.generateNodeKeys(1);
final List<DiscoveryPeer> peers = helper.createDiscoveryPeers(nodeKeys);
final ForkIdManager forkIdManager = mock(ForkIdManager.class);
final DiscoveryPeer sender = peers.get(0);
final Packet enrPacket = prepareForForkIdCheck(forkIdManager, nodeKeys, sender, true);
when(forkIdManager.peerCheck(any(ForkId.class))).thenReturn(true);
controller.onMessage(enrPacket, sender);
final Optional<DiscoveryPeer> maybePeer =
controller
.streamDiscoveredPeers()
.filter(p -> p.getId().equals(sender.getId()))
.findFirst();
assertThat(maybePeer.isPresent()).isTrue();
assertThat(maybePeer.get().getForkId().isPresent()).isTrue();
verify(controller, times(1)).connectOnRlpxLayer(eq(maybePeer.get()));
}
@Test
public void shouldFiltersOnForkIdFailure() {
final List<NodeKey> nodeKeys = PeerDiscoveryTestHelper.generateNodeKeys(1);
final List<DiscoveryPeer> peers = helper.createDiscoveryPeers(nodeKeys);
final ForkIdManager forkIdManager = mock(ForkIdManager.class);
final DiscoveryPeer sender = peers.get(0);
final Packet enrPacket = prepareForForkIdCheck(forkIdManager, nodeKeys, sender, true);
when(forkIdManager.peerCheck(any(ForkId.class))).thenReturn(false);
controller.onMessage(enrPacket, sender);
final Optional<DiscoveryPeer> maybePeer =
controller
.streamDiscoveredPeers()
.filter(p -> p.getId().equals(sender.getId()))
.findFirst();
assertThat(maybePeer.isPresent()).isTrue();
assertThat(maybePeer.get().getForkId().isPresent()).isTrue();
verify(controller, never()).connectOnRlpxLayer(eq(maybePeer.get()));
}
@Test
public void shouldStillCallConnectIfNoForkIdSent() {
final List<NodeKey> nodeKeys = PeerDiscoveryTestHelper.generateNodeKeys(1);
final List<DiscoveryPeer> peers = helper.createDiscoveryPeers(nodeKeys);
final DiscoveryPeer sender = peers.get(0);
final Packet enrPacket =
prepareForForkIdCheck(mock(ForkIdManager.class), nodeKeys, sender, false);
controller.onMessage(enrPacket, sender);
final Optional<DiscoveryPeer> maybePeer =
controller
.streamDiscoveredPeers()
.filter(p -> p.getId().equals(sender.getId()))
.findFirst();
assertThat(maybePeer.isPresent()).isTrue();
assertThat(maybePeer.get().getForkId().isPresent()).isFalse();
verify(controller, times(1)).connectOnRlpxLayer(eq(maybePeer.get()));
}
@NotNull
private Packet prepareForForkIdCheck(
final ForkIdManager forkIdManager,
final List<NodeKey> nodeKeys,
final DiscoveryPeer sender,
final boolean sendForkId) {
final HashMap<PacketType, Bytes> packetTypeBytesHashMap = new HashMap<>();
final OutboundMessageHandler outboundMessageHandler =
(dp, pa) -> packetTypeBytesHashMap.put(pa.getType(), pa.getHash());
final Cache<Bytes, Packet> enrs =
CacheBuilder.newBuilder()
.maximumSize(50)
.expireAfterWrite(1, TimeUnit.NANOSECONDS)
.ticker(
new Ticker() {
int tickCount = 1;
@Override
public long read() {
return tickCount += 10;
}
})
.build();
controller =
getControllerBuilder()
.peers(sender)
.outboundMessageHandler(outboundMessageHandler)
.enrCache(enrs)
.filterOnForkId(true)
.forkIdManager(forkIdManager)
.build();
// Mock the creation of the PING packet, so that we can control the hash, which gets validated
// when receiving the PONG.
final PingPacketData mockPing =
PingPacketData.create(
Optional.ofNullable(localPeer.getEndpoint()), sender.getEndpoint(), UInt64.ONE);
final Packet mockPacket = Packet.create(PacketType.PING, mockPing, nodeKeys.get(0));
mockPingPacketCreation(mockPacket);
controller.start();
final PongPacketData pongRequestPacketData =
PongPacketData.create(localPeer.getEndpoint(), mockPacket.getHash(), UInt64.ONE);
final Packet pongPacket =
Packet.create(PacketType.PONG, pongRequestPacketData, nodeKeys.get(0));
controller.onMessage(pongPacket, sender);
final NodeRecord nodeRecord = createNodeRecord(nodeKeys.get(0), sendForkId);
final ENRResponsePacketData enrResponsePacketData =
ENRResponsePacketData.create(
packetTypeBytesHashMap.get(PacketType.ENR_REQUEST), nodeRecord);
final Packet enrPacket =
Packet.create(PacketType.ENR_RESPONSE, enrResponsePacketData, nodeKeys.get(0));
return enrPacket;
}
private NodeRecord createNodeRecord(final NodeKey nodeKey, final boolean sendForkId) {
final UInt64 sequenceNumber = UInt64.ZERO.add(1);
final NodeRecordFactory nodeRecordFactory = NodeRecordFactory.DEFAULT;
final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance();
final Bytes addressBytes = Bytes.of(InetAddresses.forString("127.0.0.1").getAddress());
final NodeRecord nodeRecord;
if (sendForkId) {
final Bytes forkIdHash = Bytes.fromHexString("0xfc64ec04");
final Bytes forkIdNext = Bytes.fromHexString("118c30");
final ArrayList<Bytes> forkIdBytesList = new ArrayList<>();
forkIdBytesList.add(0, forkIdHash);
forkIdBytesList.add(1, forkIdNext);
nodeRecord =
nodeRecordFactory.createFromValues(
sequenceNumber,
new EnrField(EnrField.ID, IdentitySchema.V4),
new EnrField(
EnrField.PKEY_SECP256K1,
signatureAlgorithm.compressPublicKey(nodeKey.getPublicKey())),
new EnrField(EnrField.IP_V4, addressBytes),
new EnrField(EnrField.TCP, 7890),
new EnrField(EnrField.UDP, 4871),
new EnrField("eth", Collections.singletonList(forkIdBytesList)));
} else {
nodeRecord =
nodeRecordFactory.createFromValues(
sequenceNumber,
new EnrField(EnrField.ID, IdentitySchema.V4),
new EnrField(
EnrField.PKEY_SECP256K1,
signatureAlgorithm.compressPublicKey(nodeKey.getPublicKey())),
new EnrField(EnrField.IP_V4, addressBytes),
new EnrField(EnrField.TCP, 7890),
new EnrField(EnrField.UDP, 4871));
}
nodeRecord.setSignature(
nodeKey
.sign(Hash.keccak256(nodeRecord.serializeNoSignature()))
.encodedBytes()
.slice(0, 64));
return nodeRecord;
}
private static Packet mockPingPacket(final DiscoveryPeer from, final DiscoveryPeer to) {
final Packet packet = mock(Packet.class);
@ -1539,6 +1719,8 @@ public class PeerDiscoveryControllerTest {
private Cache<Bytes, Packet> enrs =
CacheBuilder.newBuilder().maximumSize(50).expireAfterWrite(10, TimeUnit.SECONDS).build();
private boolean filterOnForkId = false;
private ForkIdManager forkIdManager;
public static ControllerBuilder create() {
return new ControllerBuilder();
@ -1589,6 +1771,16 @@ public class PeerDiscoveryControllerTest {
return this;
}
public ControllerBuilder filterOnForkId(final boolean filterOnForkId) {
this.filterOnForkId = filterOnForkId;
return this;
}
public ControllerBuilder forkIdManager(final ForkIdManager forkIdManager) {
this.forkIdManager = forkIdManager;
return this;
}
PeerDiscoveryController build() {
checkNotNull(nodeKey);
if (localPeer == null) {
@ -1611,6 +1803,8 @@ public class PeerDiscoveryControllerTest {
.peerPermissions(peerPermissions)
.metricsSystem(new NoOpMetricsSystem())
.cacheForEnrRequests(enrs)
.forkIdManager(forkIdManager == null ? mock(ForkIdManager.class) : forkIdManager)
.filterOnEnrForkId(filterOnForkId)
.rlpxAgent(mock(RlpxAgent.class))
.build());
}

@ -24,6 +24,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.ethereum.forkid.ForkIdManager;
import org.hyperledger.besu.ethereum.p2p.discovery.DiscoveryPeer;
import org.hyperledger.besu.ethereum.p2p.discovery.PeerDiscoveryStatus;
import org.hyperledger.besu.ethereum.p2p.discovery.PeerDiscoveryTestHelper;
@ -71,6 +72,7 @@ public class PeerDiscoveryTableRefreshTest {
.tableRefreshIntervalMs(0)
.metricsSystem(new NoOpMetricsSystem())
.rlpxAgent(mock(RlpxAgent.class))
.forkIdManager(mock(ForkIdManager.class))
.build());
controller.start();

@ -52,14 +52,12 @@ import org.hyperledger.besu.nat.upnp.UpnpNatManager;
import org.hyperledger.besu.plugin.data.EnodeURL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.crypto.SECP256K1;
import org.assertj.core.api.Assertions;
@ -95,12 +93,11 @@ public final class DefaultP2PNetworkTest {
public void before() {
lenient().when(rlpxAgent.start()).thenReturn(CompletableFuture.completedFuture(30303));
lenient().when(rlpxAgent.stop()).thenReturn(CompletableFuture.completedFuture(null));
lenient().when(discoveryAgent.stop()).thenReturn(CompletableFuture.completedFuture(null));
lenient().when(discoveryAgent.checkForkId(any())).thenReturn(true);
lenient()
.when(discoveryAgent.start(anyInt()))
.thenAnswer(
invocation ->
CompletableFuture.completedFuture(invocation.getArgument(0, Integer.class)));
lenient().when(discoveryAgent.stop()).thenReturn(CompletableFuture.completedFuture(null));
.thenReturn(CompletableFuture.completedFuture(Integer.valueOf(30301)));
}
@Test
@ -295,7 +292,8 @@ public final class DefaultP2PNetworkTest {
network.attemptPeerConnections();
verify(rlpxAgent, times(1)).connect(peerStreamCaptor.capture());
List<? extends Peer> capturedPeers = peerStreamCaptor.getValue().collect(Collectors.toList());
final List<? extends Peer> capturedPeers =
peerStreamCaptor.getValue().collect(Collectors.toList());
assertThat(capturedPeers.contains(discoPeer)).isTrue();
assertThat(capturedPeers.size()).isEqualTo(1);
}
@ -311,7 +309,8 @@ public final class DefaultP2PNetworkTest {
network.attemptPeerConnections();
verify(rlpxAgent, times(1)).connect(peerStreamCaptor.capture());
List<? extends Peer> capturedPeers = peerStreamCaptor.getValue().collect(Collectors.toList());
final List<? extends Peer> capturedPeers =
peerStreamCaptor.getValue().collect(Collectors.toList());
assertThat(capturedPeers.contains(discoPeer)).isFalse();
assertThat(capturedPeers.size()).isEqualTo(0);
}
@ -331,7 +330,8 @@ public final class DefaultP2PNetworkTest {
network.attemptPeerConnections();
verify(rlpxAgent, times(1)).connect(peerStreamCaptor.capture());
List<? extends Peer> capturedPeers = peerStreamCaptor.getValue().collect(Collectors.toList());
final List<? extends Peer> capturedPeers =
peerStreamCaptor.getValue().collect(Collectors.toList());
assertThat(capturedPeers.size()).isEqualTo(3);
assertThat(capturedPeers.get(0)).isEqualTo(discoPeers.get(1));
assertThat(capturedPeers.get(1)).isEqualTo(discoPeers.get(0));
@ -349,7 +349,7 @@ public final class DefaultP2PNetworkTest {
@Test
public void shouldNotStartDnsDiscoveryWhenDnsURLIsNotConfigured() {
DefaultP2PNetwork testClass = network();
final DefaultP2PNetwork testClass = network();
testClass.start();
// ensure DnsDaemon is NOT present:
assertThat(testClass.getDnsDaemon()).isNotPresent();
@ -358,15 +358,15 @@ public final class DefaultP2PNetworkTest {
@Test
public void shouldStartDnsDiscoveryWhenDnsURLIsConfigured() {
// create a discovery config with a dns config
DiscoveryConfiguration disco =
final DiscoveryConfiguration disco =
DiscoveryConfiguration.create().setDnsDiscoveryURL("enrtree://mock@localhost");
// spy on config to return dns discovery config:
NetworkingConfiguration dnsConfig =
final NetworkingConfiguration dnsConfig =
when(spy(config).getDiscovery()).thenReturn(disco).getMock();
// spy on DefaultP2PNetwork
DefaultP2PNetwork testClass = (DefaultP2PNetwork) builder().config(dnsConfig).build();
final DefaultP2PNetwork testClass = (DefaultP2PNetwork) builder().config(dnsConfig).build();
testClass.start();
assertThat(testClass.getDnsDaemon()).isPresent();
@ -375,15 +375,15 @@ public final class DefaultP2PNetworkTest {
@Test
public void shouldUseDnsServerOverrideIfPresent() {
// create a discovery config with a dns config
DiscoveryConfiguration disco =
final DiscoveryConfiguration disco =
DiscoveryConfiguration.create().setDnsDiscoveryURL("enrtree://mock@localhost");
// spy on config to return dns discovery config:
NetworkingConfiguration dnsConfig = spy(config);
final NetworkingConfiguration dnsConfig = spy(config);
doReturn(disco).when(dnsConfig).getDiscovery();
doReturn(Optional.of("localhost")).when(dnsConfig).getDnsDiscoveryServerOverride();
DefaultP2PNetwork testClass = (DefaultP2PNetwork) builder().config(dnsConfig).build();
final DefaultP2PNetwork testClass = (DefaultP2PNetwork) builder().config(dnsConfig).build();
testClass.start();
// ensure we used the dns server override config when building DNSDaemon:
@ -407,7 +407,6 @@ public final class DefaultP2PNetworkTest {
.maintainedPeers(maintainedPeers)
.metricsSystem(new NoOpMetricsSystem())
.supportedCapabilities(Capability.create("eth", 63))
.storageProvider(new InMemoryKeyValueStorageProvider())
.forkIdSupplier(() -> Collections.singletonList(Bytes.EMPTY));
.storageProvider(new InMemoryKeyValueStorageProvider());
}
}

@ -20,9 +20,14 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.hamcrest.Matchers.startsWith;
import static org.hyperledger.besu.ethereum.p2p.NetworkingTestHelper.configWithRandomPorts;
import static org.junit.Assume.assumeThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.crypto.NodeKeyUtils;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider;
import org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration;
import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration;
@ -36,8 +41,8 @@ import java.util.Arrays;
import java.util.Collections;
import io.vertx.core.Vertx;
import org.apache.tuweni.bytes.Bytes;
import org.assertj.core.api.Assertions;
import org.jetbrains.annotations.NotNull;
import org.junit.After;
import org.junit.Test;
@ -55,7 +60,8 @@ public class NetworkingServiceLifecycleTest {
@Test
public void createP2PNetwork() throws IOException {
final NetworkingConfiguration config = configWithRandomPorts();
try (final P2PNetwork service = builder().build()) {
final DefaultP2PNetwork.Builder builder = getP2PNetworkBuilder();
try (final P2PNetwork service = builder.build()) {
service.start();
final EnodeURL enode = service.getLocalEnode().get();
final int udpPort = enode.getDiscoveryPortOrZero();
@ -68,12 +74,24 @@ public class NetworkingServiceLifecycleTest {
}
}
@NotNull
private DefaultP2PNetwork.Builder getP2PNetworkBuilder() {
final DefaultP2PNetwork.Builder builder = builder();
final MutableBlockchain blockchainMock = mock(MutableBlockchain.class);
final Block blockMock = mock(Block.class);
when(blockMock.getHash()).thenReturn(Hash.ZERO);
when(blockchainMock.getGenesisBlock()).thenReturn(blockMock);
builder.blockchain(blockchainMock);
builder.forks(Collections.emptyList());
return builder;
}
@Test
public void createP2PNetwork_NullHost() throws IOException {
final NetworkingConfiguration config =
NetworkingConfiguration.create()
.setDiscovery(DiscoveryConfiguration.create().setBindHost(null));
final DefaultP2PNetwork.Builder p2pNetworkBuilder = builder().config(config);
final DefaultP2PNetwork.Builder p2pNetworkBuilder = getP2PNetworkBuilder().config(config);
assertThatThrownBy(
() -> {
try (final P2PNetwork ignored = p2pNetworkBuilder.build()) {
@ -88,7 +106,7 @@ public class NetworkingServiceLifecycleTest {
final NetworkingConfiguration config =
NetworkingConfiguration.create()
.setDiscovery(DiscoveryConfiguration.create().setBindHost("fake.fake.fake"));
final DefaultP2PNetwork.Builder p2pNetworkBuilder = builder().config(config);
final DefaultP2PNetwork.Builder p2pNetworkBuilder = getP2PNetworkBuilder().config(config);
assertThatThrownBy(
() -> {
try (final P2PNetwork ignored = p2pNetworkBuilder.build()) {
@ -103,7 +121,7 @@ public class NetworkingServiceLifecycleTest {
final NetworkingConfiguration config =
NetworkingConfiguration.create()
.setDiscovery(DiscoveryConfiguration.create().setBindPort(-1));
final DefaultP2PNetwork.Builder p2pNetworkBuilder = builder().config(config);
final DefaultP2PNetwork.Builder p2pNetworkBuilder = getP2PNetworkBuilder().config(config);
assertThatThrownBy(
() -> {
try (final P2PNetwork ignored = p2pNetworkBuilder.build()) {
@ -122,7 +140,7 @@ public class NetworkingServiceLifecycleTest {
@Test
public void startStopP2PNetwork() throws IOException {
try (final P2PNetwork service = builder().build()) {
try (final P2PNetwork service = getP2PNetworkBuilder().build()) {
service.start();
service.stop();
}
@ -130,8 +148,8 @@ public class NetworkingServiceLifecycleTest {
@Test
public void startDiscoveryAgentBackToBack() throws IOException {
try (final P2PNetwork service1 = builder().build();
final P2PNetwork service2 = builder().build()) {
try (final P2PNetwork service1 = getP2PNetworkBuilder().build();
final P2PNetwork service2 = getP2PNetworkBuilder().build()) {
service1.start();
service1.stop();
service2.start();
@ -145,13 +163,13 @@ public class NetworkingServiceLifecycleTest {
"Ignored if system language is not English",
System.getProperty("user.language"),
startsWith("en"));
try (final P2PNetwork service1 = builder().config(config).build()) {
try (final P2PNetwork service1 = getP2PNetworkBuilder().config(config).build()) {
service1.start();
final NetworkingConfiguration config = configWithRandomPorts();
final int usedPort = service1.getLocalEnode().get().getDiscoveryPortOrZero();
assertThat(usedPort).isNotZero();
config.getDiscovery().setBindPort(usedPort);
try (final P2PNetwork service2 = builder().config(config).build()) {
try (final P2PNetwork service2 = getP2PNetworkBuilder().config(config).build()) {
try {
service2.start();
} catch (final Exception e) {
@ -171,7 +189,7 @@ public class NetworkingServiceLifecycleTest {
@Test
public void createP2PNetwork_NoActivePeers() throws IOException {
try (final P2PNetwork agent = builder().build()) {
try (final P2PNetwork agent = getP2PNetworkBuilder().build()) {
assertThat(agent.streamDiscoveredPeers().collect(toList())).isEmpty();
assertThat(agent.getPeers()).isEmpty();
}
@ -184,7 +202,6 @@ public class NetworkingServiceLifecycleTest {
.config(config)
.metricsSystem(new NoOpMetricsSystem())
.supportedCapabilities(Arrays.asList(Capability.create("eth", 63)))
.storageProvider(new InMemoryKeyValueStorageProvider())
.forkIdSupplier(() -> Collections.singletonList(Bytes.EMPTY));
.storageProvider(new InMemoryKeyValueStorageProvider());
}
}

@ -23,6 +23,9 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.crypto.NodeKeyUtils;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider;
import org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration;
import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration;
@ -307,6 +310,10 @@ public class P2PNetworkTest {
}
private DefaultP2PNetwork.Builder builder() {
final MutableBlockchain blockchainMock = mock(MutableBlockchain.class);
final Block blockMock = mock(Block.class);
when(blockMock.getHash()).thenReturn(Hash.ZERO);
when(blockchainMock.getGenesisBlock()).thenReturn(blockMock);
return DefaultP2PNetwork.builder()
.vertx(vertx)
.config(config)
@ -314,6 +321,7 @@ public class P2PNetworkTest {
.metricsSystem(new NoOpMetricsSystem())
.supportedCapabilities(Arrays.asList(Capability.create("eth", 63)))
.storageProvider(new InMemoryKeyValueStorageProvider())
.forkIdSupplier(() -> Collections.singletonList(Bytes.EMPTY));
.forks(Collections.emptyList())
.blockchain(blockchainMock);
}
}

@ -24,6 +24,9 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.crypto.NodeKeyUtils;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider;
import org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration;
import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration;
@ -391,7 +394,7 @@ public class P2PPlainNetworkTest {
}
private byte[] buildPaddedMessage(final int messageSize) {
byte[] bytes = new byte[messageSize];
final byte[] bytes = new byte[messageSize];
Arrays.fill(bytes, (byte) 9);
return bytes;
}
@ -416,7 +419,7 @@ public class P2PPlainNetworkTest {
final Path targetFilePath = createTemporaryFile("nsscfg");
Files.write(targetFilePath, updated.getBytes(Charsets.UTF_8));
ret = targetFilePath;
} catch (IOException e) {
} catch (final IOException e) {
throw new RuntimeException("Error populating nss config file", e);
}
return ret;
@ -427,7 +430,7 @@ public class P2PPlainNetworkTest {
try {
tempFile = File.createTempFile("temp", suffix);
tempFile.deleteOnExit();
} catch (IOException e) {
} catch (final IOException e) {
throw new RuntimeException("Error creating temporary file", e);
}
return tempFile.toPath();
@ -482,13 +485,17 @@ public class P2PPlainNetworkTest {
.withCrlPath(toPath(String.format(crl, name)));
break;
}
} catch (Exception e) {
} catch (final Exception e) {
throw new RuntimeException(e);
}
return Optional.of(builder.build());
}
private DefaultP2PNetwork.Builder builder(final String name) {
final MutableBlockchain blockchainMock = mock(MutableBlockchain.class);
final Block blockMock = mock(Block.class);
when(blockMock.getHash()).thenReturn(Hash.ZERO);
when(blockchainMock.getGenesisBlock()).thenReturn(blockMock);
return DefaultP2PNetwork.builder()
.vertx(vertx)
.config(config)
@ -497,6 +504,7 @@ public class P2PPlainNetworkTest {
.metricsSystem(new NoOpMetricsSystem())
.supportedCapabilities(Arrays.asList(Capability.create("eth", 63)))
.storageProvider(new InMemoryKeyValueStorageProvider())
.forkIdSupplier(() -> Collections.singletonList(Bytes.EMPTY));
.forks(Collections.emptyList())
.blockchain(blockchainMock);
}
}

Loading…
Cancel
Save