Use the node's configuration to decide if adding a peer with DNS in the enode is allowed (#5584)

* Use the node's configuration to decide if adding a peer with DNS in the enode is allowed

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Update command test mocks

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Update besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java

Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>
Signed-off-by: Matt Whitehead <matthew1001@hotmail.com>

* Address PR comments. Add a reference in the change log. Fix failing integration test.

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Add the same DNS-config checking logic to admin_removePeer, along with a unit test file for it

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Tweak the change log

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Add clearer error messages for the cases where enode DNS is disabled (but a hostname one has been specified in the URL) or where DNS name resolution failed

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Spotless Java fixes

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Fix copyright for new file

Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>
Signed-off-by: Matt Whitehead <matthew1001@hotmail.com>

* Address PR comments (mainly copyright & constant renaming)

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* move changelog entry to 23.4.4

Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>

---------

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>
Signed-off-by: Matt Whitehead <matthew1001@hotmail.com>
Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>
Co-authored-by: Matthew Whitehead <matthew1001@gmail.com>
Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>
pull/5627/head
Matt Whitehead 1 year ago committed by GitHub
parent 8f9882f768
commit 5bff76f107
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 19
      CHANGELOG.md
  2. 17
      besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java
  3. 1
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  4. 1
      besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java
  5. 1
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java
  6. 13
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminAddPeer.java
  7. 20
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminModifyPeer.java
  8. 13
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminRemovePeer.java
  9. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcError.java
  10. 11
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/AdminJsonRpcMethods.java
  11. 9
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java
  12. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java
  13. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java
  14. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java
  15. 2
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java
  16. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java
  17. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java
  18. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java
  19. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java
  20. 78
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminAddPeerTest.java
  21. 258
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminRemovePeerTest.java
  22. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java

@ -1,6 +1,19 @@
# Changelog
## 23.4.2
## 23.4.4
### Breaking Changes
### Additions and Improvements
### Bug Fixes
- Use the node's configuration to determine if DNS enode URLs are allowed in calls to `admin_addPeer` and `admin_removePeer` [#5584](https://github.com/hyperledger/besu/pull/5584)
### Download Links
---
## 23.4.3
### Breaking Changes
- Move blockchain related variables in a dedicated storage, to pave the way to future optimizations [#5471](https://github.com/hyperledger/besu/pull/5471). The migration is performed automatically at startup,
@ -24,6 +37,10 @@ and in case a rollback is needed, before installing a previous version, the migr
### Download Links
## 23.4.2
- Was not released (failed burn-in test)
---
## 23.4.1

@ -87,6 +87,7 @@ import org.hyperledger.besu.ethereum.p2p.network.NoopP2PNetwork;
import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork;
import org.hyperledger.besu.ethereum.p2p.network.ProtocolManager;
import org.hyperledger.besu.ethereum.p2p.peers.DefaultPeer;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration;
import org.hyperledger.besu.ethereum.p2p.permissions.PeerPermissions;
import org.hyperledger.besu.ethereum.p2p.permissions.PeerPermissionsDenylist;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.netty.TLSConfiguration;
@ -191,6 +192,7 @@ public class RunnerBuilder {
private JsonRpcIpcConfiguration jsonRpcIpcConfiguration;
private boolean legacyForkIdEnabled;
private Optional<Long> rpcMaxLogsRange;
private Optional<EnodeDnsConfiguration> enodeDnsConfiguration;
/**
* Add Vertx.
@ -584,6 +586,18 @@ public class RunnerBuilder {
return this;
}
/**
* Add enode DNS configuration
*
* @param enodeDnsConfiguration the DNS configuration for enodes
* @return the runner builder
*/
public RunnerBuilder enodeDnsConfiguration(final EnodeDnsConfiguration enodeDnsConfiguration) {
this.enodeDnsConfiguration =
enodeDnsConfiguration != null ? Optional.of(enodeDnsConfiguration) : Optional.empty();
return this;
}
/**
* Build Runner instance.
*
@ -1224,7 +1238,8 @@ public class RunnerBuilder {
dataDir,
besuController.getProtocolManager().ethContext().getEthPeers(),
consensusEngineServer,
rpcMaxLogsRange);
rpcMaxLogsRange,
enodeDnsConfiguration);
methods.putAll(besuController.getAdditionalJsonRpcMethods(jsonRpcApis));
final var pluginMethods =

@ -3103,6 +3103,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.storageProvider(keyValueStorageProvider(keyValueStorageName))
.rpcEndpointService(rpcEndpointServiceImpl)
.rpcMaxLogsRange(rpcMaxLogsRange)
.enodeDnsConfiguration(getEnodeDnsConfiguration())
.build();
addShutdownHook(runner);

@ -291,6 +291,7 @@ public abstract class CommandTestAbstract {
when(mockRunnerBuilder.rpcEndpointService(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.legacyForkId(anyBoolean())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.rpcMaxLogsRange(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.enodeDnsConfiguration(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.build()).thenReturn(mockRunner);
final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance();

@ -184,6 +184,7 @@ public class JsonRpcTestMethodsFactory {
dataDir,
ethPeers,
Vertx.vertx(new VertxOptions().setWorkerPoolSize(1)),
Optional.empty(),
Optional.empty());
}
}

@ -19,10 +19,13 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcRespon
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork;
import org.hyperledger.besu.ethereum.p2p.peers.DefaultPeer;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
import org.hyperledger.besu.ethereum.p2p.peers.Peer;
import org.hyperledger.besu.plugin.data.EnodeURL;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -30,8 +33,9 @@ public class AdminAddPeer extends AdminModifyPeer {
private static final Logger LOG = LoggerFactory.getLogger(AdminAddPeer.class);
public AdminAddPeer(final P2PNetwork peerNetwork) {
super(peerNetwork);
public AdminAddPeer(
final P2PNetwork peerNetwork, final Optional<EnodeDnsConfiguration> enodeDnsConfiguration) {
super(peerNetwork, enodeDnsConfiguration);
}
@Override
@ -42,7 +46,10 @@ public class AdminAddPeer extends AdminModifyPeer {
@Override
protected JsonRpcResponse performOperation(final Object id, final String enode) {
LOG.debug("Adding ({}) to peers", enode);
final EnodeURL enodeURL = EnodeURLImpl.fromString(enode);
final EnodeURL enodeURL =
this.enodeDnsConfiguration.isEmpty()
? EnodeURLImpl.fromString(enode)
: EnodeURLImpl.fromString(enode, enodeDnsConfiguration.get());
final Peer peer = DefaultPeer.fromEnodeURL(enodeURL);
final boolean addedToNetwork = peerNetwork.addMaintainedConnectionPeer(peer);
return new JsonRpcSuccessResponse(id, addedToNetwork);

@ -21,13 +21,19 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorR
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork;
import org.hyperledger.besu.ethereum.p2p.network.exceptions.P2PDisabledException;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration;
import java.util.Optional;
public abstract class AdminModifyPeer implements JsonRpcMethod {
protected final P2PNetwork peerNetwork;
protected final Optional<EnodeDnsConfiguration> enodeDnsConfiguration;
protected AdminModifyPeer(final P2PNetwork peerNetwork) {
protected AdminModifyPeer(
final P2PNetwork peerNetwork, final Optional<EnodeDnsConfiguration> enodeDnsConfiguration) {
this.peerNetwork = peerNetwork;
this.enodeDnsConfiguration = enodeDnsConfiguration;
}
@Override
@ -49,8 +55,16 @@ public abstract class AdminModifyPeer implements JsonRpcMethod {
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), JsonRpcError.ENODE_ID_INVALID);
} else {
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), JsonRpcError.PARSE_ERROR);
if (e.getMessage().endsWith("Invalid ip address.")) {
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), JsonRpcError.DNS_NOT_ENABLED);
} else if (e.getMessage().endsWith("dns-update-enabled flag is false.")) {
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), JsonRpcError.CANT_RESOLVE_PEER_ENODE_DNS);
} else {
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), JsonRpcError.PARSE_ERROR);
}
}
} catch (final P2PDisabledException e) {
return new JsonRpcErrorResponse(

@ -19,9 +19,12 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcRespon
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork;
import org.hyperledger.besu.ethereum.p2p.peers.DefaultPeer;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
import org.hyperledger.besu.plugin.data.EnodeURL;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -29,8 +32,9 @@ public class AdminRemovePeer extends AdminModifyPeer {
private static final Logger LOG = LoggerFactory.getLogger(AdminRemovePeer.class);
public AdminRemovePeer(final P2PNetwork peerNetwork) {
super(peerNetwork);
public AdminRemovePeer(
final P2PNetwork peerNetwork, final Optional<EnodeDnsConfiguration> enodeDnsConfiguration) {
super(peerNetwork, enodeDnsConfiguration);
}
@Override
@ -41,7 +45,10 @@ public class AdminRemovePeer extends AdminModifyPeer {
@Override
protected JsonRpcResponse performOperation(final Object id, final String enode) {
LOG.debug("Remove ({}) from peer cache", enode);
final EnodeURL enodeURL = EnodeURLImpl.fromString(enode);
final EnodeURL enodeURL =
this.enodeDnsConfiguration.isEmpty()
? EnodeURLImpl.fromString(enode)
: EnodeURLImpl.fromString(enode, enodeDnsConfiguration.get());
final boolean result =
peerNetwork.removeMaintainedConnectionPeer(DefaultPeer.fromEnodeURL(enodeURL));
return new JsonRpcSuccessResponse(id, result);

@ -162,6 +162,8 @@ public enum JsonRpcError {
VALUE_NOT_ZERO(-50100, "We cannot transfer ether in a private transaction yet."),
CANT_CONNECT_TO_LOCAL_PEER(-32100, "Cannot add local node as peer."),
CANT_RESOLVE_PEER_ENODE_DNS(-32100, "Cannot resolve enode DNS hostname"),
DNS_NOT_ENABLED(-32100, "Enode DNS support is disabled"),
// Invalid input errors
ENODE_ID_INVALID(

@ -29,11 +29,13 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.PluginsReloadC
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.eth.manager.EthPeers;
import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration;
import org.hyperledger.besu.nat.NatService;
import org.hyperledger.besu.plugin.BesuPlugin;
import java.math.BigInteger;
import java.util.Map;
import java.util.Optional;
public class AdminJsonRpcMethods extends ApiGroupJsonRpcMethods {
@ -45,6 +47,7 @@ public class AdminJsonRpcMethods extends ApiGroupJsonRpcMethods {
private final NatService natService;
private final Map<String, BesuPlugin> namedPlugins;
private final EthPeers ethPeers;
private final Optional<EnodeDnsConfiguration> enodeDnsConfiguration;
public AdminJsonRpcMethods(
final String clientVersion,
@ -54,7 +57,8 @@ public class AdminJsonRpcMethods extends ApiGroupJsonRpcMethods {
final BlockchainQueries blockchainQueries,
final Map<String, BesuPlugin> namedPlugins,
final NatService natService,
final EthPeers ethPeers) {
final EthPeers ethPeers,
final Optional<EnodeDnsConfiguration> enodeDnsConfiguration) {
this.clientVersion = clientVersion;
this.networkId = networkId;
this.genesisConfigOptions = genesisConfigOptions;
@ -63,6 +67,7 @@ public class AdminJsonRpcMethods extends ApiGroupJsonRpcMethods {
this.namedPlugins = namedPlugins;
this.natService = natService;
this.ethPeers = ethPeers;
this.enodeDnsConfiguration = enodeDnsConfiguration;
}
@Override
@ -73,8 +78,8 @@ public class AdminJsonRpcMethods extends ApiGroupJsonRpcMethods {
@Override
protected Map<String, JsonRpcMethod> create() {
return mapOf(
new AdminAddPeer(p2pNetwork),
new AdminRemovePeer(p2pNetwork),
new AdminAddPeer(p2pNetwork, enodeDnsConfiguration),
new AdminRemovePeer(p2pNetwork, enodeDnsConfiguration),
new AdminNodeInfo(
clientVersion,
networkId,

@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthPeers;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability;
import org.hyperledger.besu.ethereum.permissioning.AccountLocalConfigPermissioningController;
import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController;
@ -76,13 +77,12 @@ public class JsonRpcMethodsFactory {
final Path dataDir,
final EthPeers ethPeers,
final Vertx consensusEngineServer,
final Optional<Long> maxLogRange) {
final Optional<Long> maxLogRange,
final Optional<EnodeDnsConfiguration> enodeDnsConfiguration) {
final Map<String, JsonRpcMethod> enabled = new HashMap<>();
if (!rpcApis.isEmpty()) {
final JsonRpcMethod modules = new RpcModules(rpcApis);
enabled.put(modules.getName(), modules);
final List<JsonRpcMethods> availableApiGroups =
List.of(
new AdminJsonRpcMethods(
@ -93,7 +93,8 @@ public class JsonRpcMethodsFactory {
blockchainQueries,
namedPlugins,
natService,
ethPeers),
ethPeers,
enodeDnsConfiguration),
new DebugJsonRpcMethods(
blockchainQueries,
protocolContext,

@ -191,6 +191,7 @@ public abstract class AbstractJsonRpcHttpServiceTest {
folder.getRoot().toPath(),
mock(EthPeers.class),
syncVertx,
Optional.empty(),
Optional.empty());
}

@ -124,6 +124,7 @@ public class JsonRpcHttpServiceHostAllowlistTest {
folder.getRoot().toPath(),
mock(EthPeers.class),
vertx,
Optional.empty(),
Optional.empty()));
service = createJsonRpcHttpService();
service.start().join();

@ -154,6 +154,7 @@ public class JsonRpcHttpServiceLoginTest {
folder.getRoot().toPath(),
mock(EthPeers.class),
vertx,
Optional.empty(),
Optional.empty()));
service = createJsonRpcHttpService();
jwtAuth = service.authenticationService.get().getJwtAuthProvider();

@ -227,6 +227,7 @@ public class JsonRpcHttpServiceRpcApisTest {
folder,
mock(EthPeers.class),
vertx,
Optional.empty(),
Optional.empty()));
final JsonRpcHttpService jsonRpcHttpService =
new JsonRpcHttpService(
@ -335,6 +336,7 @@ public class JsonRpcHttpServiceRpcApisTest {
folder,
mock(EthPeers.class),
vertx,
Optional.empty(),
Optional.empty()));
final JsonRpcHttpService jsonRpcHttpService =
new JsonRpcHttpService(

@ -133,6 +133,7 @@ public class JsonRpcHttpServiceTestBase {
folder.getRoot().toPath(),
ethPeersMock,
vertx,
Optional.empty(),
Optional.empty()));
service = createJsonRpcHttpService(createLimitedJsonRpcConfig());
service.start().join();

@ -139,6 +139,7 @@ public class JsonRpcHttpServiceTlsClientAuthTest {
folder.getRoot().toPath(),
mock(EthPeers.class),
vertx,
Optional.empty(),
Optional.empty()));
System.setProperty("javax.net.ssl.trustStore", CLIENT_AS_CA_CERT.getKeyStoreFile().toString());

@ -127,6 +127,7 @@ class JsonRpcHttpServiceTlsMisconfigurationTest {
tempDir.getRoot(),
mock(EthPeers.class),
vertx,
Optional.empty(),
Optional.empty()));
}

@ -129,6 +129,7 @@ public class JsonRpcHttpServiceTlsTest {
folder.getRoot().toPath(),
mock(EthPeers.class),
vertx,
Optional.empty(),
Optional.empty()));
service = createJsonRpcHttpService(createJsonRpcConfig());
service.start().join();

@ -26,6 +26,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcRespon
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork;
import org.hyperledger.besu.ethereum.p2p.network.exceptions.P2PDisabledException;
import org.hyperledger.besu.ethereum.p2p.peers.ImmutableEnodeDnsConfiguration;
import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
@ -39,6 +42,8 @@ public class AdminAddPeerTest {
@Mock private P2PNetwork p2pNetwork;
private AdminAddPeer method;
private AdminAddPeer methodDNSDisabled;
private AdminAddPeer methodDNSUpdateDisabled;
final String validEnode =
"enode://"
@ -48,13 +53,48 @@ public class AdminAddPeerTest {
+ "00000000000000000000000000000000"
+ "@127.0.0.1:30303";
final String validDNSEnode =
"enode://"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "@node.acme.com:30303";
final JsonRpcRequestContext validRequest =
new JsonRpcRequestContext(
new JsonRpcRequest("2.0", "admin_addPeer", new String[] {validEnode}));
final JsonRpcRequestContext validDNSRequest =
new JsonRpcRequestContext(
new JsonRpcRequest("2.0", "admin_addPeer", new String[] {validDNSEnode}));
@Before
public void setup() {
method = new AdminAddPeer(p2pNetwork);
method =
new AdminAddPeer(
p2pNetwork,
Optional.of(
ImmutableEnodeDnsConfiguration.builder()
.dnsEnabled(true)
.updateEnabled(true)
.build()));
methodDNSDisabled =
new AdminAddPeer(
p2pNetwork,
Optional.of(
ImmutableEnodeDnsConfiguration.builder()
.dnsEnabled(false)
.updateEnabled(true)
.build()));
methodDNSUpdateDisabled =
new AdminAddPeer(
p2pNetwork,
Optional.of(
ImmutableEnodeDnsConfiguration.builder()
.dnsEnabled(true)
.updateEnabled(false)
.build()));
}
@Test
@ -138,6 +178,42 @@ public class AdminAddPeerTest {
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void requestAddsValidDNSEnode() {
when(p2pNetwork.addMaintainedConnectionPeer(any())).thenReturn(true);
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(
validRequest.getRequest().getId(),
true); // DNS is mapped to an IP address, so we expect the non-DNS response
final JsonRpcResponse actualResponse = method.response(validDNSRequest);
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void requestAddsDNSEnodeButDNSDisabled() {
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(
validDNSRequest.getRequest().getId(), JsonRpcError.DNS_NOT_ENABLED);
final JsonRpcResponse actualResponse = methodDNSDisabled.response(validDNSRequest);
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void requestAddsDNSEnodeButDNSNotResolved() {
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(
validDNSRequest.getRequest().getId(), JsonRpcError.CANT_RESOLVE_PEER_ENODE_DNS);
final JsonRpcResponse actualResponse = methodDNSUpdateDisabled.response(validDNSRequest);
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void requestRefusesListOfNodes() {
final JsonRpcRequestContext request =

@ -0,0 +1,258 @@
/*
* Copyright Hyperledger Besu contributors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork;
import org.hyperledger.besu.ethereum.p2p.network.exceptions.P2PDisabledException;
import org.hyperledger.besu.ethereum.p2p.peers.ImmutableEnodeDnsConfiguration;
import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.StrictStubs.class)
public class AdminRemovePeerTest {
@Mock private P2PNetwork p2pNetwork;
private AdminRemovePeer method;
private AdminRemovePeer methodDNSDisabled;
private AdminRemovePeer methodDNSUpdateDisabled;
final String validEnode =
"enode://"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "@127.0.0.1:30303";
final String validDNSEnode =
"enode://"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "@node.acme.com:30303";
final JsonRpcRequestContext validRequest =
new JsonRpcRequestContext(
new JsonRpcRequest("2.0", "admin_removePeer", new String[] {validEnode}));
final JsonRpcRequestContext validDNSRequest =
new JsonRpcRequestContext(
new JsonRpcRequest("2.0", "admin_removePeer", new String[] {validDNSEnode}));
@Before
public void setup() {
method =
new AdminRemovePeer(
p2pNetwork,
Optional.of(
ImmutableEnodeDnsConfiguration.builder()
.dnsEnabled(true)
.updateEnabled(true)
.build()));
methodDNSDisabled =
new AdminRemovePeer(
p2pNetwork,
Optional.of(
ImmutableEnodeDnsConfiguration.builder()
.dnsEnabled(false)
.updateEnabled(true)
.build()));
methodDNSUpdateDisabled =
new AdminRemovePeer(
p2pNetwork,
Optional.of(
ImmutableEnodeDnsConfiguration.builder()
.dnsEnabled(true)
.updateEnabled(false)
.build()));
}
@Test
public void requestIsMissingParameter() {
final JsonRpcRequestContext request =
new JsonRpcRequestContext(new JsonRpcRequest("2.0", "admin_removePeer", new String[] {}));
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS);
final JsonRpcResponse actualResponse = method.response(request);
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void requestHasNullObjectParameter() {
final JsonRpcRequestContext request =
new JsonRpcRequestContext(new JsonRpcRequest("2.0", "admin_removePeer", null));
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS);
final JsonRpcResponse actualResponse = method.response(request);
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void requestHasNullArrayParameter() {
final JsonRpcRequestContext request =
new JsonRpcRequestContext(
new JsonRpcRequest("2.0", "admin_removePeer", new String[] {null}));
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS);
final JsonRpcResponse actualResponse = method.response(request);
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void requestHasInvalidEnode() {
final JsonRpcRequestContext request =
new JsonRpcRequestContext(
new JsonRpcRequest("2.0", "admin_removePeer", new String[] {"asdf"}));
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.PARSE_ERROR);
final JsonRpcResponse actualResponse = method.response(request);
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void requestHasInvalidEnodeLength() {
String invalidLengthEnode =
"enode://"
+ "0000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "@127.0.0.1:30303";
final JsonRpcRequestContext request =
new JsonRpcRequestContext(
new JsonRpcRequest("2.0", "admin_removePeer", new String[] {invalidLengthEnode}));
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.ENODE_ID_INVALID);
final JsonRpcResponse actualResponse = method.response(request);
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void requestRemovesValidEnode() {
when(p2pNetwork.removeMaintainedConnectionPeer(any())).thenReturn(true);
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(validRequest.getRequest().getId(), true);
final JsonRpcResponse actualResponse = method.response(validRequest);
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void requestRemovesValidDNSEnode() {
when(p2pNetwork.removeMaintainedConnectionPeer(any())).thenReturn(true);
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(
validRequest.getRequest().getId(),
true); // DNS is mapped to an IP address, so we expect the non-DNS response
final JsonRpcResponse actualResponse = method.response(validDNSRequest);
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void requestRemovesDNSEnodeButDNSDisabled() {
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(
validDNSRequest.getRequest().getId(), JsonRpcError.DNS_NOT_ENABLED);
final JsonRpcResponse actualResponse = methodDNSDisabled.response(validDNSRequest);
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void requestRemovesDNSEnodeButDNSNotResolved() {
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(
validDNSRequest.getRequest().getId(), JsonRpcError.CANT_RESOLVE_PEER_ENODE_DNS);
final JsonRpcResponse actualResponse = methodDNSUpdateDisabled.response(validDNSRequest);
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void requestRefusesListOfNodes() {
final JsonRpcRequestContext request =
new JsonRpcRequestContext(
new JsonRpcRequest("2.0", "admin_removePeer", new String[] {validEnode, validEnode}));
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INVALID_PARAMS);
final JsonRpcResponse actualResponse = method.response(request);
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void requestReturnsFalseIfRemoveFails() {
when(p2pNetwork.removeMaintainedConnectionPeer(any())).thenReturn(false);
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(validRequest.getRequest().getId(), false);
final JsonRpcResponse actualResponse = method.response(validRequest);
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
}
@Test
public void requestReturnsErrorWhenP2pDisabled() {
when(p2pNetwork.removeMaintainedConnectionPeer(any()))
.thenThrow(
new P2PDisabledException(
"P2P networking disabled. Unable to connect to remove peer."));
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(validRequest.getRequest().getId(), JsonRpcError.P2P_DISABLED);
final JsonRpcResponse actualResponse = method.response(validRequest);
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
}
}

@ -186,6 +186,7 @@ public class WebSocketServiceLoginTest {
folder.getRoot().toPath(),
mock(EthPeers.class),
vertx,
Optional.empty(),
Optional.empty()));
websocketMethods.putAll(rpcMethods);

Loading…
Cancel
Save