Skip to content

Commit

Permalink
Added support throughout for port 0 (auto port allocation), and look-…
Browse files Browse the repository at this point in the history
…up of ports. Also added direct integration for adding lookup of the server details. (Consensys#199)
  • Loading branch information
rojotek authored Jan 25, 2019
1 parent 1e839cc commit c4154ae
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import java.io.IOException;
import java.net.ServerSocket;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;

Expand All @@ -43,20 +44,25 @@ public static String joinPathsAsTomlListEntry(Path... paths) {
return builder.toString();
}

public static String url(String host, int port) {
return new HttpUrl.Builder().scheme("http").host(host).port(port).build().toString();
private static HttpUrl buildUrl(final String host, final int port) {
return new HttpUrl.Builder().scheme("http").host(host).port(port).build();
}

public static String urlString(String host, int port) {
return buildUrl(host, port).toString();
}

public static URL url(String host, int port) {
return buildUrl(host, port).url();
}

public static Config nodeConfig(
Path tempDir,
String nodeUrl,
int nodePort,
String nodeNetworkInterface,
String clientUrl,
int clientPort,
String clientNetworkInterface,
String nodeName,
String otherNodes,
String pubKeys,
String privKeys,
String tls,
Expand All @@ -72,14 +78,11 @@ public static Config nodeConfig(
"tls=\"" + tls + "\"\n"
+ "tlsservertrust=\"" + tlsServerTrust + "\"\n"
+ "tlsclienttrust=\"" + tlsClientTrust + "\"\n"
+ "nodeurl = \"" + nodeUrl + "\"\n"
+ "nodeport = " + nodePort + "\n"
+ "nodenetworkinterface = \"" + nodeNetworkInterface + "\"\n"
+ "clienturl = \"" + clientUrl + "\"\n"
+ "clientport = " + clientPort + "\n"
+ "clientnetworkinterface = \"" + clientNetworkInterface + "\"\n"
+ "storage = \"" + storage + "\"\n"
+ "othernodes = [\"" + otherNodes + "\"]\n"
+ "publickeys = [" + pubKeys + "]\n"
+ "privatekeys = [" + privKeys + "]\n"
+ "workdir= \"" + workDir.toString() + "\"\n";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@
import net.consensys.orion.config.Config;
import net.consensys.orion.exception.OrionErrorCode;

import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Path;
import java.util.concurrent.ExecutionException;

import io.vertx.core.Vertx;
import io.vertx.core.http.HttpClient;
Expand Down Expand Up @@ -57,27 +58,18 @@ class SingleNodeSendTest {

@BeforeAll
static void setUpSingleNode(@TempDirectory Path tempDir) throws Exception {
int nodePort = NodeUtils.freePort();
int ethPort = NodeUtils.freePort();

String baseUrl = NodeUtils.url(HOST_NAME, nodePort);
String ethUrl = NodeUtils.url(HOST_NAME, ethPort);

Path key1pub = copyResource("key1.pub", tempDir.resolve("key1.pub"));
Path key1key = copyResource("key1.key", tempDir.resolve("key1.key"));
Path key2pub = copyResource("key2.pub", tempDir.resolve("key2.pub"));
Path key2key = copyResource("key2.key", tempDir.resolve("key2.key"));

config = NodeUtils.nodeConfig(
tempDir,
baseUrl,
nodePort,
0,
"127.0.0.1",
ethUrl,
ethPort,
0,
"127.0.0.1",
"node1",
baseUrl,
joinPathsAsTomlListEntry(key1pub, key2pub),
joinPathsAsTomlListEntry(key1key, key2key),
"off",
Expand All @@ -86,10 +78,12 @@ static void setUpSingleNode(@TempDirectory Path tempDir) throws Exception {
"leveldb:database/node1");
}


@BeforeEach
void setUp() throws ExecutionException, InterruptedException {
void setUp() throws MalformedURLException {
orionLauncher = NodeUtils.startOrion(config);
vertx = vertx();
orionLauncher.addPeer(new URL(NodeUtils.urlString(HOST_NAME, orionLauncher.nodePort())));
httpClient = vertx.createHttpClient();
}

Expand Down Expand Up @@ -120,7 +114,7 @@ void corruptedPublicKey() {
}

private EthClientStub client() {
return NodeUtils.client(config.clientPort(), httpClient);
return NodeUtils.client(orionLauncher.clientPort(), httpClient);
}

/** Verifies the Orion error JSON matches the desired Orion code. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import static net.consensys.cava.io.Base64.decodeBytes;
import static net.consensys.cava.io.file.Files.copyResource;
import static net.consensys.orion.acceptance.NodeUtils.assertTransaction;
import static net.consensys.orion.acceptance.NodeUtils.freePort;
import static net.consensys.orion.acceptance.NodeUtils.joinPathsAsTomlListEntry;
import static net.consensys.orion.acceptance.NodeUtils.sendTransaction;
import static net.consensys.orion.acceptance.NodeUtils.viewTransaction;
Expand All @@ -35,7 +34,6 @@
import net.consensys.orion.network.ConcurrentNetworkNodes;
import net.consensys.orion.utils.Serializer;

import java.net.URL;
import java.nio.file.Path;
import java.sql.Connection;
import java.sql.DriverManager;
Expand Down Expand Up @@ -63,8 +61,6 @@ class DualNodesSendReceiveTest {

private Config firstNodeConfig;
private Config secondNodeConfig;
private int firstNodeClientPort;
private int secondNodeClientPort;
private ConcurrentNetworkNodes networkNodes;

private Orion firstOrionLauncher;
Expand All @@ -75,12 +71,6 @@ class DualNodesSendReceiveTest {

@BeforeEach
void setUpDualNodes(@TempDirectory Path tempDir) throws Exception {
int firstNodePort = freePort();
firstNodeClientPort = freePort();
int secondNodePort = freePort();
secondNodeClientPort = freePort();
String firstNodeBaseUrl = NodeUtils.url("127.0.0.1", firstNodePort);
String secondNodeBaseUrl = NodeUtils.url("127.0.0.1", secondNodePort);

Path key1pub = copyResource("key1.pub", tempDir.resolve("key1.pub"));
Path key1key = copyResource("key1.key", tempDir.resolve("key1.key"));
Expand All @@ -95,14 +85,11 @@ void setUpDualNodes(@TempDirectory Path tempDir) throws Exception {

firstNodeConfig = NodeUtils.nodeConfig(
tempDir,
firstNodeBaseUrl,
firstNodePort,
0,
"127.0.0.1",
NodeUtils.url("127.0.0.1", firstNodeClientPort),
firstNodeClientPort,
0,
"127.0.0.1",
"node1",
secondNodeBaseUrl,
joinPathsAsTomlListEntry(key1pub),
joinPathsAsTomlListEntry(key1key),
"off",
Expand All @@ -111,14 +98,11 @@ void setUpDualNodes(@TempDirectory Path tempDir) throws Exception {
"leveldb:database/node1");
secondNodeConfig = NodeUtils.nodeConfig(
tempDir,
secondNodeBaseUrl,
secondNodePort,
0,
"127.0.0.1",
NodeUtils.url("127.0.0.1", secondNodeClientPort),
secondNodeClientPort,
0,
"127.0.0.1",
"node2",
firstNodeBaseUrl,
joinPathsAsTomlListEntry(key2pub),
joinPathsAsTomlListEntry(key2key),
"off",
Expand All @@ -130,20 +114,20 @@ void setUpDualNodes(@TempDirectory Path tempDir) throws Exception {
firstHttpClient = vertx.createHttpClient();
secondOrionLauncher = NodeUtils.startOrion(secondNodeConfig);
secondHttpClient = vertx.createHttpClient();
networkNodes = new ConcurrentNetworkNodes(new URL(firstNodeBaseUrl));

Box.PublicKey pk1 = Box.PublicKey.fromBytes(decodeBytes(PK_1_B_64));
Box.PublicKey pk2 = Box.PublicKey.fromBytes(decodeBytes(PK_2_B_64));
networkNodes.addNode(pk1, new URL(firstNodeBaseUrl));
networkNodes.addNode(pk2, new URL(secondNodeBaseUrl));
networkNodes = new ConcurrentNetworkNodes(NodeUtils.url("127.0.0.1", firstOrionLauncher.nodePort()));

networkNodes.addNode(pk1, NodeUtils.url("127.0.0.1", firstOrionLauncher.nodePort()));
networkNodes.addNode(pk2, NodeUtils.url("127.0.0.1", secondOrionLauncher.nodePort()));
// prepare /partyinfo payload (our known peers)
RequestBody partyInfoBody =
RequestBody.create(MediaType.parse(CBOR.httpHeaderValue), Serializer.serialize(CBOR, networkNodes));
// call http endpoint
OkHttpClient httpClient = new OkHttpClient();

final String firstNodeBaseUrl = NodeUtils.urlString("127.0.0.1", firstOrionLauncher.nodePort());
Request request = new Request.Builder().post(partyInfoBody).url(firstNodeBaseUrl + "/partyinfo").build();

// first /partyinfo call may just get the one node, so wait until we get at least 2 nodes
await().atMost(5, TimeUnit.SECONDS).until(() -> getPartyInfoResponse(httpClient, request).nodeURLs().size() == 2);

Expand All @@ -167,8 +151,8 @@ void tearDown() {

@Test
void receiverCanView() {
final EthClientStub firstNode = NodeUtils.client(firstNodeClientPort, firstHttpClient);
final EthClientStub secondNode = NodeUtils.client(secondNodeClientPort, secondHttpClient);
final EthClientStub firstNode = NodeUtils.client(firstOrionLauncher.clientPort(), firstHttpClient);
final EthClientStub secondNode = NodeUtils.client(secondOrionLauncher.clientPort(), secondHttpClient);

final String digest = sendTransaction(firstNode, PK_1_B_64, PK_2_B_64);
final byte[] receivedPayload = viewTransaction(secondNode, PK_2_B_64, digest);
Expand All @@ -178,7 +162,7 @@ void receiverCanView() {

@Test
void senderCanView() {
final EthClientStub firstNode = NodeUtils.client(firstNodeConfig.clientPort(), firstHttpClient);
final EthClientStub firstNode = NodeUtils.client(firstOrionLauncher.clientPort(), firstHttpClient);

final String digest = sendTransaction(firstNode, PK_1_B_64, PK_2_B_64);
final byte[] receivedPayload = viewTransaction(firstNode, PK_1_B_64, digest);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,24 +58,18 @@ static void setUpSingleNode(@TempDirectory Path tempDir) throws Exception {
final int nodePort = freePort();
clientPort = freePort();

String baseUrl = NodeUtils.url(HOST_NAME, nodePort);
String clientUrl = NodeUtils.url(HOST_NAME, clientPort);

Path key1pub = copyResource("key1.pub", tempDir.resolve("key1.pub"));
Path key1key = copyResource("key1.key", tempDir.resolve("key1.key"));
Path key2pub = copyResource("key2.pub", tempDir.resolve("key2.pub"));
Path key2key = copyResource("key2.key", tempDir.resolve("key2.key"));

config = NodeUtils.nodeConfig(
tempDir,
baseUrl,
nodePort,
"127.0.0.1",
clientUrl,
HOST_NAME,
clientPort,
"127.0.0.1",
HOST_NAME,
"node1",
baseUrl,
joinPathsAsTomlListEntry(key1pub, key2pub),
joinPathsAsTomlListEntry(key1key, key2key),
"off",
Expand Down
24 changes: 22 additions & 2 deletions src/main/java/net/consensys/orion/cmd/Orion.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@

import java.io.IOException;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
Expand Down Expand Up @@ -398,9 +400,9 @@ public void run(PrintStream out, PrintStream err, Config config) {
vertx.createHttpServer(clientOptions).requestHandler(clientRouter::accept).exceptionHandler(log::error).listen(
completeFutureInHandler(clientFuture));

CompletableFuture<Boolean> verticleFuture = new CompletableFuture<>();
// start network discovery of other peers
discovery = new NetworkDiscovery(networkNodes, config);
CompletableFuture<Boolean> verticleFuture = new CompletableFuture<>();
vertx.deployVerticle(discovery, result -> {
if (result.succeeded()) {
verticleFuture.complete(true);
Expand All @@ -411,7 +413,13 @@ public void run(PrintStream out, PrintStream err, Config config) {

try {
CompletableFuture.allOf(nodeFuture, clientFuture, verticleFuture).get();
} catch (ExecutionException e) {
// if there is not a node url in the config, then grab the actual port and use it to set the node url.
if (!config.nodeUrl().isPresent()) {
networkNodes.setNodeUrl(
new URL("http", config.nodeNetworkInterface(), nodeHTTPServer.actualPort(), ""),
keyStore.nodeKeys());
}
} catch (ExecutionException | MalformedURLException e) {
throw new OrionStartException("Orion failed to start: " + e.getCause().getMessage(), e.getCause());
} catch (InterruptedException e) {
throw new OrionStartException("Orion was interrupted while starting services");
Expand Down Expand Up @@ -496,4 +504,16 @@ private static Config loadConfig(@Nullable Path configFile) {
throw new OrionStartException("Could not open '" + configFile.toAbsolutePath() + "': " + e.getMessage(), e);
}
}

public int nodePort() {
return nodeHTTPServer.actualPort();
}

public int clientPort() {
return clientHTTPServer.actualPort();
}

public void addPeer(final URL url) {
discovery.addPeer(url);
}
}
31 changes: 20 additions & 11 deletions src/main/java/net/consensys/orion/config/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,12 @@ private Config(Configuration configuration) {
/**
* Externally accessible URL for this node's Orion API
* <p>
* This is what is advertised to other nodes on the network and must be reachable by them.
*
* This is what is advertised to other nodes on the network and must be reachable by them. This is optional, as the
* url might be derived from the actual node port and node network interface
*
* @return URL for this node's Orion API
*/
public URL nodeUrl() {
public Optional<URL> nodeUrl() {
return getURL("nodeurl");
}

Expand All @@ -114,9 +115,12 @@ public String nodeNetworkInterface() {
/**
* URL advertised to the Ethereum client paired with this node.
*
* <p>
* This is optional, as the url might be derived from the actual client port and client network interface
*
* @return URL for this node's client API
*/
public URL clientUrl() {
public Optional<URL> clientUrl() {
return getURL("clienturl");
}

Expand Down Expand Up @@ -439,9 +443,12 @@ public Path tlsKnownServers() {
return getPath("tlsknownservers");
}

private URL getURL(String key) {
private Optional<URL> getURL(String key) {
try {
return new URL(configuration.getString(key));
if (!configuration.contains(key)) {
return Optional.empty();
}
return Optional.of(new URL(configuration.getString(key)));
} catch (MalformedURLException e) {
throw new IllegalStateException("key '" + key + "' should have been validated, yet it's invalid", e);
}
Expand All @@ -460,22 +467,22 @@ private static Schema configSchema() {

schemaBuilder.addString(
"nodeurl",
"http://127.0.0.1:8080/",
null,
"Externally accessible URL for this node's public API This is what is advertised to other nodes on the network and must be reachable by them.",
isURL());

schemaBuilder.addInteger("nodeport", 8080, "Port to listen on for the Orion API.", inRange(1, 65536));
schemaBuilder.addInteger("nodeport", 8080, "Port to listen on for the Orion API.", inRange(0, 65536));

schemaBuilder
.addString("nodenetworkinterface", "127.0.0.1", "Network interface to which the Orion API will bind.", null);

schemaBuilder.addString(
"clienturl",
"http://127.0.0.1:8888/",
null,
"Internally accessible URL for this node's public API This is what is advertised to other nodes on the network and must be reachable by them.",
isURL());

schemaBuilder.addInteger("clientport", 8888, "Port to listen on for the Ethereum client API.", inRange(1, 65536));
schemaBuilder.addInteger("clientport", 8888, "Port to listen on for the Ethereum client API.", inRange(0, 65536));

schemaBuilder.addString(
"clientnetworkinterface",
Expand Down Expand Up @@ -676,9 +683,11 @@ private static List<ConfigurationError> validateStorage(
private static List<ConfigurationError> validateConfiguration(Configuration config) {
List<ConfigurationError> errors = new ArrayList<>();

// nodeport and client port must be different (unless they are 0 and defaulted).
if (config.contains("nodeport")
&& config.contains("clientport")
&& config.getInteger("nodeport") == config.getInteger("clientport")) {
&& config.getInteger("nodeport") == config.getInteger("clientport")
&& config.getInteger("nodeport") != 0) {
errors.add(
new ConfigurationError(
config.inputPositionOf("clientport"),
Expand Down
Loading

0 comments on commit c4154ae

Please sign in to comment.