Skip to content

Commit

Permalink
OR-339: Added /knownnodes client API method (Consensys#303)
Browse files Browse the repository at this point in the history
* OR-339: Added /knownnodes client API method

* Fix errorprone warnings
  • Loading branch information
lucassaldanha authored Nov 20, 2019
1 parent ddc561f commit c801086
Show file tree
Hide file tree
Showing 5 changed files with 223 additions and 5 deletions.
3 changes: 3 additions & 0 deletions src/main/java/net/consensys/orion/cmd/Orion.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import net.consensys.orion.enclave.QueryPrivacyGroupPayload;
import net.consensys.orion.enclave.sodium.FileKeyStore;
import net.consensys.orion.enclave.sodium.SodiumEnclave;
import net.consensys.orion.http.handler.knownnodes.KnownNodesHandler;
import net.consensys.orion.http.handler.partyinfo.PartyInfoHandler;
import net.consensys.orion.http.handler.privacy.CreatePrivacyGroupHandler;
import net.consensys.orion.http.handler.privacy.DeletePrivacyGroupHandler;
Expand Down Expand Up @@ -210,6 +211,8 @@ public static void configureRoutes(

clientRouter.post("/findPrivacyGroup").consumes(JSON.httpHeaderValue).produces(JSON.httpHeaderValue).handler(
new FindPrivacyGroupHandler(queryPrivacyGroupStorage, privacyGroupStorage));

clientRouter.get("/knownnodes").produces(JSON.httpHeaderValue).handler(new KnownNodesHandler(networkNodes));
}

public Orion() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2019 ConsenSys AG.
*
* 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.
*/
package net.consensys.orion.http.handler.knownnodes;

import net.consensys.cava.crypto.sodium.Box.PublicKey;

import java.net.URL;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Objects;
import org.postgresql.util.Base64;

class KnownNode {

private final String publicKey;
private final String nodeUrl;

KnownNode(final PublicKey publicKey, final URL nodeUrl) {
this.publicKey = Base64.encodeBytes(publicKey.bytesArray());
this.nodeUrl = nodeUrl.toString();
}

@JsonCreator
KnownNode(@JsonProperty("publicKey") final String publicKey, final @JsonProperty("nodeUrl") String nodeUrl) {
this.publicKey = publicKey;
this.nodeUrl = nodeUrl;
}

@JsonProperty("publicKey")
String getPublicKey() {
return publicKey;
}

@JsonProperty("nodeUrl")
String getNodeUrl() {
return nodeUrl;
}

@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final KnownNode knownNode = (KnownNode) o;
return Objects.equal(publicKey, knownNode.publicKey) && Objects.equal(nodeUrl, knownNode.nodeUrl);
}

@Override
public int hashCode() {
return Objects.hashCode(publicKey, nodeUrl);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2019 ConsenSys AG.
*
* 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.
*/
package net.consensys.orion.http.handler.knownnodes;

import net.consensys.orion.http.server.HttpContentType;
import net.consensys.orion.network.ConcurrentNetworkNodes;
import net.consensys.orion.utils.Serializer;

import java.util.ArrayList;
import java.util.List;

import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import io.vertx.ext.web.RoutingContext;

public class KnownNodesHandler implements Handler<RoutingContext> {

private final ConcurrentNetworkNodes networkNodes;

public KnownNodesHandler(final ConcurrentNetworkNodes networkNodes) {
this.networkNodes = networkNodes;
}

@Override
public void handle(final RoutingContext routingContext) {
final List<KnownNode> knownNodes = new ArrayList<>();

networkNodes.nodePKs().forEach((publicKey, url) -> knownNodes.add(new KnownNode(publicKey, url)));

final Buffer bufferResponse = Buffer.buffer(Serializer.serialize(HttpContentType.JSON, knownNodes));

routingContext.response().end(bufferResponse);
}
}
10 changes: 5 additions & 5 deletions src/test/java/net/consensys/orion/http/handler/HandlerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,15 @@
import org.junit.jupiter.api.extension.ExtendWith;

@ExtendWith(TempDirectoryExtension.class)
abstract class HandlerTest {
public abstract class HandlerTest {

// http client
final OkHttpClient httpClient = new OkHttpClient();
String nodeBaseUrl;
String clientBaseUrl;
protected final OkHttpClient httpClient = new OkHttpClient();
protected String nodeBaseUrl;
protected String clientBaseUrl;

// these are re-built between tests
ConcurrentNetworkNodes networkNodes;
protected ConcurrentNetworkNodes networkNodes;
protected Config config;
protected Enclave enclave;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* Copyright 2019 ConsenSys AG.
*
* 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.
*/
package net.consensys.orion.http.handler.knownnodes;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

import net.consensys.cava.crypto.sodium.Box.KeyPair;
import net.consensys.cava.crypto.sodium.Box.PublicKey;
import net.consensys.cava.io.Base64;
import net.consensys.orion.http.handler.HandlerTest;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import okhttp3.Request;
import okhttp3.Response;
import org.junit.jupiter.api.Test;

class KnownNodesHandlerTest extends HandlerTest {

@Test
void shouldReturnListOfKnownNodesWhenOrionHasNodes() throws Exception {
final List<KnownNode> nodes = createNodes();
addNodesToNetwork(nodes);

final Request request = new Request.Builder().get().url(clientBaseUrl + "/knownnodes").build();
final Response response = httpClient.newCall(request).execute();
final List<KnownNode> knownNodes = readList(response);

assertEquals(nodes.size(), knownNodes.size());
assertTrue(knownNodes.containsAll(nodes));
}

@Test
void shouldReturnEmptyListWhenOrionHasNoNodes() throws Exception {
final Request request = new Request.Builder().get().url(clientBaseUrl + "/knownnodes").build();
final Response response = httpClient.newCall(request).execute();
final List<KnownNode> knownNodes = readList(response);

assertTrue(knownNodes.isEmpty());
}

@Test
void knownNodesMethodIsAvailableOnClientApi() throws Exception {
final Request request = new Request.Builder().get().url(clientBaseUrl + "/knownnodes").build();
final Response response = httpClient.newCall(request).execute();

assertEquals(200, response.code());
}

@Test
void knownNodesMethodIsNotAvailableOnNodeApi() throws Exception {
final Request request = new Request.Builder().get().url(nodeBaseUrl + "/knownnodes").build();
final Response response = httpClient.newCall(request).execute();

assertEquals(404, response.code());
}

private List<KnownNode> readList(final Response response) throws java.io.IOException {
return new ObjectMapper().readValue(response.body().bytes(), new TypeReference<>() {});
}

private List<KnownNode> createNodes() {
try {
final List<KnownNode> knownNodes = new ArrayList<>();
knownNodes.add(new KnownNode(KeyPair.random().publicKey(), new URL("http://127.0.0.1:9001/")));
knownNodes.add(new KnownNode(KeyPair.random().publicKey(), new URL("http://127.0.0.1:9002/")));
return knownNodes;
} catch (Exception e) {
fail(e);
return new ArrayList<>();
}
}

private void addNodesToNetwork(final Collection<KnownNode> nodes) {
nodes.forEach(node -> {
try {
final PublicKey publicKey = PublicKey.fromBytes(Base64.decodeBytes(node.getPublicKey()));
final URL nodeUrl = new URL(node.getNodeUrl());
networkNodes.addNode(Collections.singletonList(publicKey), nodeUrl);
} catch (MalformedURLException e) {
fail(e);
}
});
}

}

0 comments on commit c801086

Please sign in to comment.