[PRIV] Prepare private transaction support (#538)

* Add Orion module

* Add integration tests

* Use ephemeral instance of Orion for integration test

- Start orion on random port
- test payloads can be send and received

* update build image

* Use snapshot build of orion

Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
Ivaylo Kirilov 6 years ago committed by Rob Dawson
parent cf7d659bc4
commit 14a67e8b82
  1. 1
      build.gradle
  2. 1
      config/build.gradle
  3. 14
      orion/build.gradle
  4. 87
      orion/src/integration-test/java/tech/pegasys/pantheon/orion/OrionTest.java
  5. 77
      orion/src/main/java/tech/pegasys/pantheon/orion/Orion.java
  6. 49
      orion/src/main/java/tech/pegasys/pantheon/orion/OrionConfiguration.java
  7. 40
      orion/src/main/java/tech/pegasys/pantheon/orion/types/ReceiveContent.java
  8. 32
      orion/src/main/java/tech/pegasys/pantheon/orion/types/ReceiveResponse.java
  9. 51
      orion/src/main/java/tech/pegasys/pantheon/orion/types/SendContent.java
  10. 31
      orion/src/main/java/tech/pegasys/pantheon/orion/types/SendResponse.java
  11. 1
      settings.gradle
  12. 2
      testutil/build.gradle
  13. 151
      testutil/src/main/java/tech/pegasys/orion/testutil/OrionTestHarness.java
  14. 1
      testutil/src/main/resources/orion_key_0.key
  15. 1
      testutil/src/main/resources/orion_key_0.pub
  16. 1
      testutil/src/main/resources/orion_key_1.key
  17. 1
      testutil/src/main/resources/orion_key_1.pub

@ -79,6 +79,7 @@ allprojects {
repositories {
if ("$System.env.JENKINS_URL" == 'https://jenkins.pegasys.tech/') {
maven { url "https://nexus.int.pegasys.tech/repository/consensys-pegasys/" }
maven { url "https://nexus.int.pegasys.tech/repository/jcenter/" }
} else {
jcenter()

@ -38,6 +38,7 @@ dependencies {
testImplementation 'junit:junit'
testImplementation 'org.assertj:assertj-core'
testImplementation 'org.mockito:mockito-core'
testImplementation 'net.consensys:orion:0.1.0-SNAPSHOT'
}
configurations { testArtifacts }

@ -0,0 +1,14 @@
dependencies {
implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.8'
implementation 'com.squareup.okhttp3:okhttp:3.12.1'
implementation 'org.apache.logging.log4j:log4j-api'
// test dependencies.
testImplementation 'junit:junit'
// integration test dependacies.
integrationTestImplementation 'junit:junit'
integrationTestImplementation project(':testutil')
integrationTestImplementation 'net.consensys:orion:0.1.0-SNAPSHOT'
}

@ -0,0 +1,87 @@
/*
* 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 tech.pegasys.pantheon.orion;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import tech.pegasys.orion.testutil.OrionTestHarness;
import tech.pegasys.pantheon.orion.types.ReceiveContent;
import tech.pegasys.pantheon.orion.types.ReceiveResponse;
import tech.pegasys.pantheon.orion.types.SendContent;
import tech.pegasys.pantheon.orion.types.SendResponse;
import java.io.IOException;
import java.util.List;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
public class OrionTest {
@ClassRule public static final TemporaryFolder folder = new TemporaryFolder();
private static final String PAYLOAD = "a wonderful transaction";
private static Orion orion;
private static OrionTestHarness testHarness;
@BeforeClass
public static void setUpOnce() throws Exception {
folder.create();
testHarness = OrionTestHarness.create(folder.newFolder().toPath());
OrionConfiguration orionConfiguration = OrionConfiguration.createDefault();
orionConfiguration.setUrl(testHarness.getConfig().clientUrl().toString());
orion = new Orion(orionConfiguration);
}
@AfterClass
public static void tearDownOnce() {
testHarness.getOrion().stop();
}
@Test
public void testUpCheck() throws IOException {
assertTrue(orion.upCheck());
}
@Test
public void testSendAndReceive() throws IOException {
List<String> publicKeys = testHarness.getPublicKeys();
SendContent sc = new SendContent(PAYLOAD, publicKeys.get(0), new String[] {publicKeys.get(1)});
SendResponse sr = orion.send(sc);
ReceiveContent rc = new ReceiveContent(sr.getKey(), publicKeys.get(1));
ReceiveResponse rr = orion.receive(rc);
assertEquals(PAYLOAD, new String(rr.getPayload(), UTF_8));
}
@Test(expected = IOException.class)
public void whenUpCheckFailsThrows() throws IOException {
OrionConfiguration configuration = OrionConfiguration.createDefault();
configuration.setUrl("http:");
Orion broken = new Orion(configuration);
broken.upCheck();
}
}

@ -0,0 +1,77 @@
/*
* 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 tech.pegasys.pantheon.orion;
import tech.pegasys.pantheon.orion.types.ReceiveContent;
import tech.pegasys.pantheon.orion.types.ReceiveResponse;
import tech.pegasys.pantheon.orion.types.SendContent;
import tech.pegasys.pantheon.orion.types.SendResponse;
import java.io.IOException;
import com.fasterxml.jackson.databind.ObjectMapper;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Orion {
private static final MediaType JSON = MediaType.parse("application/json");
private static final ObjectMapper objectMapper = new ObjectMapper();
private static final Logger LOG = LogManager.getLogger();
private String url;
private OkHttpClient client;
public Orion(final OrionConfiguration orionConfiguration) {
this.url = orionConfiguration.getUrl();
this.client = new OkHttpClient();
}
public Boolean upCheck() throws IOException {
Request request = new Request.Builder().url(url + "/upcheck").get().build();
try (Response response = client.newCall(request).execute()) {
return response.isSuccessful();
} catch (IOException e) {
LOG.error("Orion failed to execute upcheck");
throw new IOException("Failed to perform upcheck", e);
}
}
public SendResponse send(final SendContent content) throws IOException {
return executePost("/send", objectMapper.writeValueAsString(content), SendResponse.class);
}
public ReceiveResponse receive(final ReceiveContent content) throws IOException {
return executePost("/receive", objectMapper.writeValueAsString(content), ReceiveResponse.class);
}
private <T> T executePost(final String path, final String content, final Class<T> responseType)
throws IOException {
OkHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create(JSON, content);
Request request = new Request.Builder().url(url + path).post(body).build();
try (Response response = client.newCall(request).execute()) {
return objectMapper.readValue(response.body().string(), responseType);
} catch (IOException e) {
LOG.error("Orion failed to execute ", path);
throw new IOException("Failed to execute post", e);
}
}
}

@ -0,0 +1,49 @@
/*
* 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 tech.pegasys.pantheon.orion;
public class OrionConfiguration {
private static final String DEFAULT_ORION_URL = "http://localhost:8888";
private boolean enabled;
private String url;
public static OrionConfiguration createDefault() {
final OrionConfiguration config = new OrionConfiguration();
config.setEnabled(false);
config.setUrl(DEFAULT_ORION_URL);
return config;
}
@Override
public String toString() {
return "OrionConfiguration{" + "enabled=" + enabled + ", url='" + url + '\'' + '}';
}
public void setUrl(final String url) {
this.url = url;
}
public String getUrl() {
return this.url;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
}

@ -0,0 +1,40 @@
/*
* 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 tech.pegasys.pantheon.orion.types;
public class ReceiveContent {
private String key;
private String to;
public ReceiveContent(final String key, final String to) {
this.key = key;
this.to = to;
}
public String getKey() {
return key;
}
public void setKey(final String key) {
this.key = key;
}
public String getTo() {
return to;
}
public void setTo(final String to) {
this.to = to;
}
}

@ -0,0 +1,32 @@
/*
* 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 tech.pegasys.pantheon.orion.types;
public class ReceiveResponse {
byte[] payload;
public byte[] getPayload() {
return payload;
}
public void setPayload(final byte[] payload) {
this.payload = payload;
}
public ReceiveResponse(final byte[] payload) {
this.payload = payload;
}
public ReceiveResponse() {}
}

@ -0,0 +1,51 @@
/*
* 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 tech.pegasys.pantheon.orion.types;
import static java.nio.charset.StandardCharsets.UTF_8;
public class SendContent {
private byte[] payload;
private String from;
private String[] to;
public SendContent(final String payload, final String from, final String[] to) {
this.payload = payload.getBytes(UTF_8);
this.from = from;
this.to = to;
}
public byte[] getPayload() {
return payload;
}
public void setPayload(final String payload) {
this.payload = payload.getBytes(UTF_8);
}
public String getFrom() {
return from;
}
public void setFrom(final String from) {
this.from = from;
}
public String[] getTo() {
return to;
}
public void setTo(final String[] to) {
this.to = to;
}
}

@ -0,0 +1,31 @@
/*
* 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 tech.pegasys.pantheon.orion.types;
public class SendResponse {
String key;
public String getKey() {
return key;
}
public void setKey(final String key) {
this.key = key;
}
public SendResponse(final String key) {
this.key = key;
}
public SendResponse() {}
}

@ -37,3 +37,4 @@ include 'testutil'
include 'util'
include 'errorprone-checks'
include 'quickstart'
include 'orion'

@ -28,4 +28,6 @@ jar {
dependencies {
implementation 'com.fasterxml.jackson.core:jackson-databind'
implementation 'com.google.guava:guava'
implementation 'com.squareup.okhttp3:okhttp'
implementation 'net.consensys:orion:0.1.0-SNAPSHOT'
}

@ -0,0 +1,151 @@
/*
* 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 tech.pegasys.orion.testutil;
import static com.google.common.io.Files.readLines;
import static net.consensys.cava.io.file.Files.copyResource;
import java.io.IOException;
import java.net.ServerSocket;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Collectors;
import com.google.common.base.Charsets;
import net.consensys.orion.cmd.Orion;
import net.consensys.orion.config.Config;
public class OrionTestHarness {
private final Orion orion;
private final Config config;
private static final String HOST = "127.0.0.1";
private OrionTestHarness(final Orion orion, final Config config) {
this.orion = orion;
this.config = config;
}
public static OrionTestHarness create(final Path tempDir) throws Exception {
int nodePort = freePort();
int clientPort = freePort();
String nodeUrl = String.format("http://%s:%s", HOST, nodePort);
String clientUrl = String.format("http://%s:%s", HOST, clientPort);
Path key1pub = copyResource("orion_key_0.pub", tempDir.resolve("orion_key_0.pub"));
Path key1key = copyResource("orion_key_0.key", tempDir.resolve("orion_key_0.key"));
Path key2pub = copyResource("orion_key_1.pub", tempDir.resolve("orion_key_1.pub"));
Path key2key = copyResource("orion_key_1.key", tempDir.resolve("orion_key_1.key"));
// @formatter:off
String confString =
"tls=\"off\"\n"
+ "tlsservertrust=\"tofu\"\n"
+ "tlsclienttrust=\"tofu\"\n"
+ "nodeurl = \""
+ nodeUrl
+ "\"\n"
+ "nodeport = "
+ nodePort
+ "\n"
+ "nodenetworkinterface = \""
+ HOST
+ "\"\n"
+ "clienturl = \""
+ clientUrl
+ "\"\n"
+ "clientport = "
+ clientPort
+ "\n"
+ "clientnetworkinterface = \""
+ HOST
+ "\"\n"
+ "storage = \"leveldb:database/orion_node\"\n"
+ "othernodes = [\""
+ nodeUrl
+ "\"]\n"
+ "publickeys = ["
+ joinPathsAsTomlListEntry(key1pub, key2pub)
+ "]\n"
+ "privatekeys = ["
+ joinPathsAsTomlListEntry(key1key, key2key)
+ "]\n"
+ "workdir= \""
+ tempDir.toString()
+ "\"\n";
// @formatter:on
Config config = Config.load(confString);
final Orion orion = new Orion();
orion.run(System.out, System.err, config);
return new OrionTestHarness(orion, config);
}
public Orion getOrion() {
return orion;
}
public Config getConfig() {
return config;
}
public List<String> getPublicKeys() {
return config
.publicKeys()
.stream()
.map(OrionTestHarness::readFile)
.collect(Collectors.toList());
}
public List<String> getPrivateKeys() {
return config
.privateKeys()
.stream()
.map(OrionTestHarness::readFile)
.collect(Collectors.toList());
}
private static String readFile(final Path path) {
try {
return readLines(path.toFile(), Charsets.UTF_8).get(0);
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
private static int freePort() throws Exception {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
}
}
private static String joinPathsAsTomlListEntry(final Path... paths) {
StringBuilder builder = new StringBuilder();
boolean first = true;
for (Path path : paths) {
if (!first) {
builder.append(",");
}
first = false;
builder.append("\"").append(path.toAbsolutePath().toString()).append("\"");
}
return builder.toString();
}
}

@ -0,0 +1 @@
{"data":{"bytes":"hBsuQsGJzx4QHmFmBkNoI7YGnTmaZP4P+wBOdu56ljk="},"type":"unlocked"}

@ -0,0 +1 @@
A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=

@ -0,0 +1 @@
{"data":{"bytes":"wjeHURxQJUqZvhjMv+lxoRlXYnX/mpm0Iu/ldBr32Qs="},"type":"unlocked"}

@ -0,0 +1 @@
Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs=
Loading…
Cancel
Save