Skip to content

Commit

Permalink
[PRIV] Implement privacy precompiled contract (PegaSysEng#696)
Browse files Browse the repository at this point in the history
* Implement privacy precompiled contract

* Update gradle dependency version

* Fix privacy precompiled contract unit tests

* Update Privacy Integration test
  • Loading branch information
Puneetha17 authored and tmohay committed Feb 4, 2019
1 parent 8553f6a commit 1e3933e
Show file tree
Hide file tree
Showing 11 changed files with 225 additions and 19 deletions.
2 changes: 2 additions & 0 deletions ethereum/core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ dependencies {
integrationTestImplementation 'junit:junit'
integrationTestImplementation 'org.assertj:assertj-core'
integrationTestImplementation 'org.mockito:mockito-core'
integrationTestImplementation project(':testutil')
integrationTestImplementation 'net.consensys:orion'

testSupportImplementation project(path: ':config', configuration: 'testSupportArtifacts')
testSupportImplementation project(':testutil')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* 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.ethereum.mainnet.precompiles.privacy;

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.ethereum.mainnet.SpuriousDragonGasCalculator;
import tech.pegasys.pantheon.orion.Orion;
import tech.pegasys.pantheon.orion.types.SendRequest;
import tech.pegasys.pantheon.orion.types.SendResponse;
import tech.pegasys.pantheon.util.bytes.BytesValue;

import java.io.IOException;
import java.util.List;

import com.google.common.collect.Lists;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

public class PrivacyPrecompiledContractIntegrationTest {

@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());

orion = new Orion(testHarness.clientUrl());
}

@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();

SendRequest sc =
new SendRequest(PAYLOAD, publicKeys.get(0), Lists.newArrayList(publicKeys.get(1)));
SendResponse sr = orion.send(sc);

PrivacyPrecompiledContract privacyPrecompiledContract =
new PrivacyPrecompiledContract(new SpuriousDragonGasCalculator(), publicKeys.get(0), orion);

BytesValue result =
privacyPrecompiledContract.compute(BytesValue.wrap(sr.getKey().getBytes(UTF_8)));

String expected = new String(result.extractArray(), UTF_8);

assertEquals(PAYLOAD, expected);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,29 @@
*/
package tech.pegasys.pantheon.ethereum.core;

import static java.nio.charset.StandardCharsets.UTF_8;

import java.io.File;
import java.io.IOException;
import java.net.URI;

import com.google.common.io.Files;

public class PrivacyParameters {
private static final String ORION_URL = "http://localhost:8888";
public static final URI DEFAULT_ORION_URL = URI.create(ORION_URL);

private Integer privacyAddress;
private boolean enabled;
private String url;
private File publicKey;
private String publicKey;

public File getPublicKey() {
public String getPublicKey() {
return publicKey;
}

public void setPublicKey(final File publicKey) {
this.publicKey = publicKey;
public void setPublicKeyUsingFile(final File publicKeyFile) throws IOException {
this.publicKey = Files.asCharSource(publicKeyFile, UTF_8).read();
}

public static PrivacyParameters noPrivacy() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,57 @@
*/
package tech.pegasys.pantheon.ethereum.mainnet.precompiles.privacy;

import static java.nio.charset.StandardCharsets.UTF_8;

import tech.pegasys.pantheon.ethereum.core.Gas;
import tech.pegasys.pantheon.ethereum.core.PrivacyParameters;
import tech.pegasys.pantheon.ethereum.mainnet.AbstractPrecompiledContract;
import tech.pegasys.pantheon.ethereum.vm.GasCalculator;
import tech.pegasys.pantheon.orion.Orion;
import tech.pegasys.pantheon.orion.types.ReceiveRequest;
import tech.pegasys.pantheon.orion.types.ReceiveResponse;
import tech.pegasys.pantheon.util.bytes.BytesValue;

import java.io.IOException;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class PrivacyPrecompiledContract extends AbstractPrecompiledContract {
private PrivacyParameters privacyParameters;
private final Orion orion;
private final String orionPublicKey;

private static final Logger LOG = LogManager.getLogger();

public PrivacyPrecompiledContract(
final GasCalculator gasCalculator, final PrivacyParameters privacyParameters) {
this(gasCalculator, privacyParameters.getPublicKey(), new Orion(privacyParameters.getUrl()));
}

PrivacyPrecompiledContract(
final GasCalculator gasCalculator, final String publicKey, final Orion orion) {
super("Privacy", gasCalculator);
this.orion = orion;
this.orionPublicKey = publicKey;
}

@Override
public Gas gasRequirement(final BytesValue input) {
return null; // We need to write the contract first.
return Gas.of(40_000L); // Not sure
}

@Override
public BytesValue compute(final BytesValue input) {
return null;
try {
String key = new String(input.extractArray(), UTF_8);
ReceiveRequest receiveRequest = new ReceiveRequest(key, orionPublicKey);
ReceiveResponse receiveResponse = orion.receive(receiveRequest);
LOG.info("Got the response as ", receiveResponse.getPayload());
return BytesValue.wrap(receiveResponse.getPayload());
// pass it to private tx processor
} catch (IOException e) {
LOG.fatal("Orion threw an unhandled exception.", e);
return BytesValue.EMPTY;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* 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.ethereum.mainnet.precompiles.privacy;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import tech.pegasys.pantheon.ethereum.mainnet.SpuriousDragonGasCalculator;
import tech.pegasys.pantheon.orion.Orion;
import tech.pegasys.pantheon.orion.types.ReceiveRequest;
import tech.pegasys.pantheon.orion.types.ReceiveResponse;
import tech.pegasys.pantheon.util.bytes.BytesValue;

import java.io.IOException;

import org.junit.Before;
import org.junit.Test;

public class PrivacyPrecompiledContractTest {
private final String actual = "Test String";
private final String publicKey = "public key";
private final BytesValue key = BytesValue.wrap(actual.getBytes(UTF_8));
private PrivacyPrecompiledContract privacyPrecompiledContract;
private PrivacyPrecompiledContract brokenPrivateTransactionHandler;

Orion mockOrion() throws IOException {
Orion mockOrion = mock(Orion.class);
ReceiveResponse response = new ReceiveResponse(actual.getBytes(UTF_8));
when(mockOrion.receive(any(ReceiveRequest.class))).thenReturn(response);
return mockOrion;
}

Orion brokenMockOrion() throws IOException {
Orion mockOrion = mock(Orion.class);
when(mockOrion.receive(any(ReceiveRequest.class))).thenThrow(IOException.class);
return mockOrion;
}

@Before
public void setUp() throws IOException {
privacyPrecompiledContract =
new PrivacyPrecompiledContract(new SpuriousDragonGasCalculator(), publicKey, mockOrion());
brokenPrivateTransactionHandler =
new PrivacyPrecompiledContract(
new SpuriousDragonGasCalculator(), publicKey, brokenMockOrion());
}

@Test
public void testPrivacyPrecompiledContract() {

final BytesValue expected = privacyPrecompiledContract.compute(key);

String exp = new String(expected.extractArray(), UTF_8);
assertThat(exp).isEqualTo(actual);
}

@Test
public void enclaveIsDownWhileHandling() {
final BytesValue expected = brokenPrivateTransactionHandler.compute(key);

assertThat(expected).isEqualTo(BytesValue.EMPTY);
}
}
2 changes: 1 addition & 1 deletion gradle/versions.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,4 @@ dependencyManagement {

dependency 'org.xerial.snappy:snappy-java:1.1.7.2'
}
}
}
2 changes: 1 addition & 1 deletion orion/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ dependencies {
// integration test dependacies.
integrationTestImplementation 'junit:junit'
integrationTestImplementation project(':testutil')
integrationTestImplementation 'net.consensys:orion'
integrationTestImplementation 'net.consensys:orion:0.1.1-SNAPSHOT'

}
6 changes: 5 additions & 1 deletion orion/src/main/java/tech/pegasys/pantheon/orion/Orion.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ public class Orion {
private static final Logger LOG = LogManager.getLogger();

private String url;
private OkHttpClient client;
private final OkHttpClient client;

public Orion() {
this.client = new OkHttpClient();
}

public Orion(final String orionUrl) {
this.url = orionUrl;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -744,9 +744,8 @@ private PermissioningConfiguration permissioningConfiguration() {
return permissioningConfiguration;
}

private PrivacyParameters orionConfiguration() {
private PrivacyParameters orionConfiguration() throws IOException {

// Check that mining options are able top work or send an error
CommandLineUtils.checkOptionDependencies(
logger,
commandLine,
Expand All @@ -756,10 +755,16 @@ private PrivacyParameters orionConfiguration() {
"--privacy-url", "--privacy-public-key-file", "--privacy-precompiled-address"));

final PrivacyParameters privacyParameters = PrivacyParameters.noPrivacy();
privacyParameters.setEnabled(privacyEnabled);
privacyParameters.setUrl(privacyUrl.toString());
privacyParameters.setPublicKey(privacyPublicKeyFile);
privacyParameters.setPrivacyAddress(privacyPrecompiledAddress);
if (privacyEnabled) {
privacyParameters.setEnabled(privacyEnabled);
privacyParameters.setUrl(privacyUrl.toString());
if (privacyPublicKeyFile != null) {
privacyParameters.setPublicKeyUsingFile(privacyPublicKeyFile);
} else {
throw new IOException("Please specify Enclave public Key file path to Enable Privacy");
}
privacyParameters.setPrivacyAddress(privacyPrecompiledAddress);
}
return privacyParameters;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
public class PantheonCommandTest extends CommandTestAbstract {

private final String ORION_URI = "http://1.2.3.4:5555";
private final String ORION_PUBLIC_KEY = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=";
private final String VALID_NODE_ID =
"6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0";
static final String PERMISSIONING_CONFIG_TOML = "permissioning_config.toml";
Expand Down Expand Up @@ -1811,14 +1812,14 @@ public void fullCLIOptionsShownWhenNotInDockerContainer() {

@Test
public void mustUseOrionUriAndOptions() throws IOException {
final File file = new File("./specific/public_key");
final URL configFile = Resources.getResource("orion_publickey.pub");

parseCommand(
"--privacy-enabled",
"--privacy-url",
ORION_URI,
"--privacy-public-key-file",
file.getPath());
configFile.getPath());

final ArgumentCaptor<PrivacyParameters> orionArg =
ArgumentCaptor.forClass(PrivacyParameters.class);
Expand All @@ -1827,7 +1828,7 @@ public void mustUseOrionUriAndOptions() throws IOException {
verify(mockControllerBuilder).build();

assertThat(orionArg.getValue().getUrl()).isEqualTo(ORION_URI);
assertThat(orionArg.getValue().getPublicKey()).isEqualTo(file);
assertThat(orionArg.getValue().getPublicKey()).isEqualTo(ORION_PUBLIC_KEY);

assertThat(commandOutput.toString()).isEmpty();
assertThat(commandErrorOutput.toString()).isEmpty();
Expand Down
1 change: 1 addition & 0 deletions pantheon/src/test/resources/orion_publickey.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=

0 comments on commit 1e3933e

Please sign in to comment.