diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a2b86f087..55d1dd98ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java index 96df5e7252..d54a914942 100644 --- a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java @@ -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 rpcMaxLogsRange; + private Optional 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 = diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index c9a9b599dc..87fc5a545d 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -3103,6 +3103,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable { .storageProvider(keyValueStorageProvider(keyValueStorageName)) .rpcEndpointService(rpcEndpointServiceImpl) .rpcMaxLogsRange(rpcMaxLogsRange) + .enodeDnsConfiguration(getEnodeDnsConfiguration()) .build(); addShutdownHook(runner); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java index b5c31a34de..3b9aafe35d 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java @@ -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(); diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java index 2a4021c7e9..518d5b8c36 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java @@ -184,6 +184,7 @@ public class JsonRpcTestMethodsFactory { dataDir, ethPeers, Vertx.vertx(new VertxOptions().setWorkerPoolSize(1)), + Optional.empty(), Optional.empty()); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminAddPeer.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminAddPeer.java index ddaa577fd1..4bd352aaa2 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminAddPeer.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminAddPeer.java @@ -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) { + 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); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminModifyPeer.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminModifyPeer.java index ca0fc91b74..8cb11b9dcb 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminModifyPeer.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminModifyPeer.java @@ -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; - protected AdminModifyPeer(final P2PNetwork peerNetwork) { + protected AdminModifyPeer( + final P2PNetwork peerNetwork, final Optional 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( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminRemovePeer.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminRemovePeer.java index 248024c398..0cb654bb12 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminRemovePeer.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminRemovePeer.java @@ -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) { + 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); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcError.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcError.java index bc633fdeff..8b7da6bb7a 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcError.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcError.java @@ -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( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/AdminJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/AdminJsonRpcMethods.java index 61109f73c8..286758cb76 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/AdminJsonRpcMethods.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/AdminJsonRpcMethods.java @@ -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 namedPlugins; private final EthPeers ethPeers; + private final Optional enodeDnsConfiguration; public AdminJsonRpcMethods( final String clientVersion, @@ -54,7 +57,8 @@ public class AdminJsonRpcMethods extends ApiGroupJsonRpcMethods { final BlockchainQueries blockchainQueries, final Map namedPlugins, final NatService natService, - final EthPeers ethPeers) { + final EthPeers ethPeers, + final Optional 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 create() { return mapOf( - new AdminAddPeer(p2pNetwork), - new AdminRemovePeer(p2pNetwork), + new AdminAddPeer(p2pNetwork, enodeDnsConfiguration), + new AdminRemovePeer(p2pNetwork, enodeDnsConfiguration), new AdminNodeInfo( clientVersion, networkId, diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java index e0b1eb7b6a..5effa4dd5d 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java @@ -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 maxLogRange) { + final Optional maxLogRange, + final Optional enodeDnsConfiguration) { final Map enabled = new HashMap<>(); - if (!rpcApis.isEmpty()) { final JsonRpcMethod modules = new RpcModules(rpcApis); enabled.put(modules.getName(), modules); - final List availableApiGroups = List.of( new AdminJsonRpcMethods( @@ -93,7 +93,8 @@ public class JsonRpcMethodsFactory { blockchainQueries, namedPlugins, natService, - ethPeers), + ethPeers, + enodeDnsConfiguration), new DebugJsonRpcMethods( blockchainQueries, protocolContext, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java index d2979a1bf6..1b7a536d0b 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java @@ -191,6 +191,7 @@ public abstract class AbstractJsonRpcHttpServiceTest { folder.getRoot().toPath(), mock(EthPeers.class), syncVertx, + Optional.empty(), Optional.empty()); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java index af10a62833..226197c5de 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java @@ -124,6 +124,7 @@ public class JsonRpcHttpServiceHostAllowlistTest { folder.getRoot().toPath(), mock(EthPeers.class), vertx, + Optional.empty(), Optional.empty())); service = createJsonRpcHttpService(); service.start().join(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java index 081d91a8f8..5d7e3391d0 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java @@ -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(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java index 7a61d5ce9a..06d428ab34 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java @@ -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( diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java index 29cc186c6e..0b3b9441dc 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java @@ -133,6 +133,7 @@ public class JsonRpcHttpServiceTestBase { folder.getRoot().toPath(), ethPeersMock, vertx, + Optional.empty(), Optional.empty())); service = createJsonRpcHttpService(createLimitedJsonRpcConfig()); service.start().join(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java index 389bb83d2a..fcbfb399d1 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java @@ -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()); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java index e1710b4a88..1e6d1f169c 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java @@ -127,6 +127,7 @@ class JsonRpcHttpServiceTlsMisconfigurationTest { tempDir.getRoot(), mock(EthPeers.class), vertx, + Optional.empty(), Optional.empty())); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java index 0b051e935e..f45410cc9c 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java @@ -129,6 +129,7 @@ public class JsonRpcHttpServiceTlsTest { folder.getRoot().toPath(), mock(EthPeers.class), vertx, + Optional.empty(), Optional.empty())); service = createJsonRpcHttpService(createJsonRpcConfig()); service.start().join(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminAddPeerTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminAddPeerTest.java index 24ca1482b6..8c476722d3 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminAddPeerTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminAddPeerTest.java @@ -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 = diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminRemovePeerTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminRemovePeerTest.java new file mode 100644 index 0000000000..21c2cf2462 --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AdminRemovePeerTest.java @@ -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); + } +} diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java index 0da62372a5..4b9dc5e384 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java @@ -186,6 +186,7 @@ public class WebSocketServiceLoginTest { folder.getRoot().toPath(), mock(EthPeers.class), vertx, + Optional.empty(), Optional.empty())); websocketMethods.putAll(rpcMethods);