mirror of https://github.com/hyperledger/besu
[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
parent
cf7d659bc4
commit
14a67e8b82
@ -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() {} |
||||
} |
@ -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…
Reference in new issue