Output enode URL on startup (#1137)

Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
Lucas Saldanha 6 years ago committed by GitHub
parent 65f674d73b
commit 1cd9e10b86
  1. 35
      ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/NetEnode.java
  2. 3
      ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/response/JsonRpcError.java
  3. 18
      ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/NetEnodeTest.java
  4. 6
      ethereum/mock-p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/testing/MockNetwork.java
  5. 6
      ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/NoopP2PNetwork.java
  6. 9
      ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/api/P2PNetwork.java
  7. 27
      ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/netty/NettyP2PNetwork.java
  8. 15
      ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/NettyP2PNetworkTest.java

@ -17,17 +17,13 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcError;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcErrorResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse;
import tech.pegasys.pantheon.ethereum.p2p.P2pDisabledException;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.peers.Peer;
import tech.pegasys.pantheon.util.enode.EnodeURL;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Optional;
public class NetEnode implements JsonRpcMethod {
private static final Logger LOG = LogManager.getLogger();
private final P2PNetwork p2pNetwork;
public NetEnode(final P2PNetwork p2pNetwork) {
@ -41,26 +37,23 @@ public class NetEnode implements JsonRpcMethod {
@Override
public JsonRpcResponse response(final JsonRpcRequest req) {
try {
if (p2pNetwork.isP2pEnabled()) {
String enodeURI = p2pNetwork.getAdvertisedPeer().map(Peer::getEnodeURLString).orElse("");
if (!enodeURI.isEmpty()) {
return new JsonRpcSuccessResponse(req.getId(), enodeURI);
} else {
return p2pDisabledResponse(req);
}
} else {
return p2pDisabledResponse(req);
}
} catch (final P2pDisabledException e) {
if (!p2pNetwork.isP2pEnabled()) {
return p2pDisabledResponse(req);
} catch (final Exception e) {
LOG.error("Error processing request: " + req, e);
throw e;
}
final Optional<EnodeURL> enodeURL = p2pNetwork.getSelfEnodeURL();
if (!enodeURL.isPresent()) {
return enodeUrlNotAvailable(req);
}
return new JsonRpcSuccessResponse(req.getId(), enodeURL.get().toString());
}
private JsonRpcErrorResponse p2pDisabledResponse(final JsonRpcRequest req) {
return new JsonRpcErrorResponse(req.getId(), JsonRpcError.P2P_DISABLED);
}
private JsonRpcErrorResponse enodeUrlNotAvailable(final JsonRpcRequest req) {
return new JsonRpcErrorResponse(req.getId(), JsonRpcError.ENODE_NOT_AVAILABLE);
}
}

@ -25,7 +25,10 @@ public enum JsonRpcError {
METHOD_NOT_FOUND(-32601, "Method not found"),
INVALID_PARAMS(-32602, "Invalid params"),
INTERNAL_ERROR(-32603, "Internal error"),
// P2P related errors
P2P_DISABLED(-32000, "P2P has been disabled. This functionality is not available"),
ENODE_NOT_AVAILABLE(-32000, "Enode URL not available"),
// Filter & Subscription Errors
FILTER_NOT_FOUND(-32000, "Filter not found"),

@ -23,8 +23,8 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer;
import tech.pegasys.pantheon.ethereum.p2p.peers.Peer;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import tech.pegasys.pantheon.util.enode.EnodeURL;
import java.util.Optional;
@ -37,8 +37,6 @@ import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class NetEnodeTest {
private static final String TESTED_METHOD_NAME = "net_enode";
private NetEnode method;
private final BytesValue nodeId =
@ -46,7 +44,7 @@ public class NetEnodeTest {
"0x0f1b319e32017c3fcb221841f0f978701b4e9513fe6a567a2db43d43381a9c7e3dfe7cae13cbc2f56943400bacaf9082576ab087cd51983b17d729ae796f6807");
private final DefaultPeer defaultPeer = new DefaultPeer(nodeId, "1.2.3.4", 7890, 30303);
private final Optional<Peer> advertisedPeer = Optional.of(defaultPeer);
private final Optional<EnodeURL> enodeURL = Optional.of(defaultPeer.getEnodeURL());
@Mock private P2PNetwork p2PNetwork;
@ -57,17 +55,17 @@ public class NetEnodeTest {
@Test
public void shouldReturnExpectedMethodName() {
assertThat(method.getName()).isEqualTo(TESTED_METHOD_NAME);
assertThat(method.getName()).isEqualTo("net_enode");
}
@Test
public void shouldReturnEnode() {
when(p2PNetwork.isP2pEnabled()).thenReturn(true);
doReturn(advertisedPeer).when(p2PNetwork).getAdvertisedPeer();
doReturn(enodeURL).when(p2PNetwork).getSelfEnodeURL();
final JsonRpcRequest request = netEnodeRequest();
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(request.getId(), advertisedPeer.get().getEnodeURLString());
new JsonRpcSuccessResponse(request.getId(), enodeURL.get().toString());
assertThat(method.response(request)).isEqualToComparingFieldByField(expectedResponse);
}
@ -86,16 +84,16 @@ public class NetEnodeTest {
@Test
public void shouldReturnErrorWhenP2PEnabledButNoEnodeFound() {
when(p2PNetwork.isP2pEnabled()).thenReturn(true);
doReturn(Optional.empty()).when(p2PNetwork).getAdvertisedPeer();
doReturn(Optional.empty()).when(p2PNetwork).getSelfEnodeURL();
final JsonRpcRequest request = netEnodeRequest();
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(request.getId(), JsonRpcError.P2P_DISABLED);
new JsonRpcErrorResponse(request.getId(), JsonRpcError.ENODE_NOT_AVAILABLE);
assertThat(method.response(request)).isEqualToComparingFieldByField(expectedResponse);
}
private JsonRpcRequest netEnodeRequest() {
return new JsonRpcRequest("2.0", TESTED_METHOD_NAME, new Object[] {});
return new JsonRpcRequest("2.0", "net_enode", new Object[] {});
}
}

@ -25,6 +25,7 @@ import tech.pegasys.pantheon.ethereum.p2p.wire.PeerInfo;
import tech.pegasys.pantheon.ethereum.p2p.wire.messages.DisconnectMessage.DisconnectReason;
import tech.pegasys.pantheon.ethereum.permissioning.NodeLocalConfigPermissioningController;
import tech.pegasys.pantheon.util.Subscribers;
import tech.pegasys.pantheon.util.enode.EnodeURL;
import java.net.SocketAddress;
import java.util.ArrayList;
@ -212,6 +213,11 @@ public final class MockNetwork {
public Optional<NodeLocalConfigPermissioningController> getNodeWhitelistController() {
return Optional.empty();
}
@Override
public Optional<EnodeURL> getSelfEnodeURL() {
return Optional.empty();
}
}
/**

@ -20,6 +20,7 @@ import tech.pegasys.pantheon.ethereum.p2p.peers.Peer;
import tech.pegasys.pantheon.ethereum.p2p.wire.Capability;
import tech.pegasys.pantheon.ethereum.p2p.wire.PeerInfo;
import tech.pegasys.pantheon.ethereum.permissioning.NodeLocalConfigPermissioningController;
import tech.pegasys.pantheon.util.enode.EnodeURL;
import java.io.IOException;
import java.util.Collection;
@ -91,6 +92,11 @@ public class NoopP2PNetwork implements P2PNetwork {
return Optional.empty();
}
@Override
public Optional<EnodeURL> getSelfEnodeURL() {
return Optional.empty();
}
@Override
public void close() throws IOException {}

@ -16,6 +16,7 @@ import tech.pegasys.pantheon.ethereum.p2p.peers.Peer;
import tech.pegasys.pantheon.ethereum.p2p.wire.Capability;
import tech.pegasys.pantheon.ethereum.p2p.wire.PeerInfo;
import tech.pegasys.pantheon.ethereum.permissioning.NodeLocalConfigPermissioningController;
import tech.pegasys.pantheon.util.enode.EnodeURL;
import java.io.Closeable;
import java.util.Collection;
@ -127,4 +128,12 @@ public interface P2PNetwork extends Closeable {
* @return an instance of NodeLocalConfigPermissioningController, if set.
*/
Optional<NodeLocalConfigPermissioningController> getNodeWhitelistController();
/**
* Returns the EnodeURL used to identify this peer in the network.
*
* @return the enodeURL associated with this node if P2P has been enabled. Returns empty
* otherwise.
*/
Optional<EnodeURL> getSelfEnodeURL();
}

@ -52,6 +52,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
@ -161,6 +162,10 @@ public class NettyP2PNetwork implements P2PNetwork {
private final LabelledMetric<Counter> outboundMessagesCounter;
private final String advertisedHost;
private EnodeURL ourEnodeURL;
private final Optional<NodeLocalConfigPermissioningController> nodeWhitelistController;
private final Optional<NodePermissioningController> nodePermissioningController;
private final Optional<Blockchain> blockchain;
@ -304,6 +309,7 @@ public class NettyP2PNetwork implements P2PNetwork {
this.nodeWhitelistController = nodeLocalConfigPermissioningController;
this.nodePermissioningController = nodePermissioningController;
this.blockchain = Optional.ofNullable(blockchain);
this.advertisedHost = config.getDiscovery().getAdvertisedHost();
}
private Supplier<Integer> pendingTaskCounter(final EventLoopGroup eventLoopGroup) {
@ -519,6 +525,9 @@ public class NettyP2PNetwork implements P2PNetwork {
"NettyP2PNetwork permissioning needs to listen to BlockAddedEvents. Blockchain can't be null.");
}
}
this.ourEnodeURL = buildSelfEnodeURL();
LOG.info("Enode URL {}", ourEnodeURL.toString());
}
private Consumer<PeerBondedEvent> handlePeerBondedEvent() {
@ -672,6 +681,24 @@ public class NettyP2PNetwork implements P2PNetwork {
return nodeWhitelistController;
}
@Override
public Optional<EnodeURL> getSelfEnodeURL() {
return Optional.ofNullable(ourEnodeURL);
}
private EnodeURL buildSelfEnodeURL() {
final String nodeId = ourPeerInfo.getNodeId().toUnprefixedString();
final int listeningPort = ourPeerInfo.getPort();
final OptionalInt discoveryPort =
peerDiscoveryAgent
.getAdvertisedPeer()
.map(p -> OptionalInt.of(p.getEndpoint().getUdpPort()))
.filter(port -> port.getAsInt() != listeningPort)
.orElse(OptionalInt.empty());
return new EnodeURL(nodeId, advertisedHost, listeningPort, discoveryPort);
}
private void onConnectionEstablished(final PeerConnection connection) {
connections.registerConnection(connection);
connectCallbacks.forEach(callback -> callback.accept(connection));

@ -798,6 +798,21 @@ public final class NettyP2PNetworkTest {
verify(peerConnection).disconnect(DisconnectReason.REQUESTED);
}
@Test
public void beforeStartingNetworkEnodeURLShouldNotBePresent() {
final NettyP2PNetwork nettyP2PNetwork = mockNettyP2PNetwork();
assertThat(nettyP2PNetwork.getSelfEnodeURL()).isNotPresent();
}
@Test
public void afterStartingNetworkEnodeURLShouldBePresent() {
final NettyP2PNetwork nettyP2PNetwork = mockNettyP2PNetwork();
nettyP2PNetwork.start();
assertThat(nettyP2PNetwork.getSelfEnodeURL()).isPresent();
}
private BlockAddedEvent blockAddedEvent() {
return mock(BlockAddedEvent.class);
}

Loading…
Cancel
Save