[PRIV] Implement privacy precompiled contract (#696)

* Implement privacy precompiled contract

* Update gradle dependency version

* Fix privacy precompiled contract unit tests

* Update Privacy Integration test

Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
Puneetha Karamsetty 6 years ago committed by Rob Dawson
parent fcb6efe532
commit 61bdcc879a
  1. 2
      ethereum/core/build.gradle
  2. 82
      ethereum/core/src/integration-test/java/tech/pegasys/pantheon/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractIntegrationTest.java
  3. 13
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/PrivacyParameters.java
  4. 36
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContract.java
  5. 76
      ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractTest.java
  6. 2
      gradle/versions.gradle
  7. 2
      orion/build.gradle
  8. 6
      orion/src/main/java/tech/pegasys/pantheon/orion/Orion.java
  9. 17
      pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java
  10. 7
      pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java
  11. 1
      pantheon/src/test/resources/orion_publickey.pub

@ -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')

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

@ -12,9 +12,14 @@
*/
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);
@ -22,14 +27,14 @@ public class PrivacyParameters {
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() {

@ -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;
}
}
}

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

@ -82,4 +82,4 @@ dependencyManagement {
dependency 'org.xerial.snappy:snappy-java:1.1.7.2'
}
}
}

@ -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'
}

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

@ -744,9 +744,8 @@ public class PantheonCommand implements DefaultCommandValues, Runnable {
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,
@ -756,10 +755,16 @@ public class PantheonCommand implements DefaultCommandValues, Runnable {
"--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;
}

@ -72,6 +72,7 @@ import picocli.CommandLine;
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";
@ -1811,14 +1812,14 @@ public class PantheonCommandTest extends CommandTestAbstract {
@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);
@ -1827,7 +1828,7 @@ public class PantheonCommandTest extends CommandTestAbstract {
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();

@ -0,0 +1 @@
A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=
Loading…
Cancel
Save