From 0500d18950297f4640ea16de1bd12dd4c163c981 Mon Sep 17 00:00:00 2001 From: Ivaylo Kirilov Date: Tue, 27 Aug 2019 11:18:50 +0100 Subject: [PATCH] [PAN-2789] Add ethSigner acceptance test (#1655) Signed-off-by: Adrian Sutton --- acceptance-tests/build.gradle | 5 +- ...ectSuccessfulEeaGetTransactionReceipt.java | 8 +- .../dsl/ethsigner/EthSignerClient.java | 107 +++++++++++++++ .../dsl/ethsigner/EthSignerClientTest.java | 122 ++++++++++++++++++ .../ethsigner/PrivateTransactionRequest.java | 101 +++++++++++++++ .../ethsigner/testutil/EthSignerConfig.java | 93 +++++++++++++ .../testutil/EthSignerTestHarness.java | 28 ++++ .../testutil/EthSignerTestHarnessFactory.java | 84 ++++++++++++ .../acceptance/dsl/node/PantheonNode.java | 8 ++ .../eea/PrivateTransactionBuilder.java | 2 +- .../privacy/EthSignerAcceptanceTest.java | 81 ++++++++++++ gradle/versions.gradle | 9 +- testutil/build.gradle | 1 + ...b557e8fb62b89f4916b721be55ceb828dbd73.json | 1 + 14 files changed, 644 insertions(+), 6 deletions(-) create mode 100644 acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/EthSignerClient.java create mode 100644 acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/EthSignerClientTest.java create mode 100644 acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/PrivateTransactionRequest.java create mode 100644 acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/testutil/EthSignerConfig.java create mode 100644 acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/testutil/EthSignerTestHarness.java create mode 100644 acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/testutil/EthSignerTestHarnessFactory.java create mode 100644 acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/web3j/privacy/EthSignerAcceptanceTest.java create mode 100644 testutil/src/main/resources/ethSignerKey--fe3b557e8fb62b89f4916b721be55ceb828dbd73.json diff --git a/acceptance-tests/build.gradle b/acceptance-tests/build.gradle index b540c0ce6b..ee01331fe8 100644 --- a/acceptance-tests/build.gradle +++ b/acceptance-tests/build.gradle @@ -49,8 +49,11 @@ dependencies { testImplementation 'org.awaitility:awaitility' testImplementation 'org.java-websocket:Java-WebSocket' testImplementation 'org.web3j:abi' - testImplementation 'org.web3j:core' + testImplementation 'org.web3j:eea' testImplementation 'org.web3j:crypto' + testImplementation 'tech.pegasys.ethsigner.internal:core' + testImplementation 'tech.pegasys.ethsigner.internal:file-based' + testImplementation 'tech.pegasys.ethsigner.internal:signing-api' testImplementation 'tech.pegasys.pantheon:plugin-api' } diff --git a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/condition/eea/ExpectSuccessfulEeaGetTransactionReceipt.java b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/condition/eea/ExpectSuccessfulEeaGetTransactionReceipt.java index b36f9da22b..470db925f8 100644 --- a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/condition/eea/ExpectSuccessfulEeaGetTransactionReceipt.java +++ b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/condition/eea/ExpectSuccessfulEeaGetTransactionReceipt.java @@ -13,6 +13,7 @@ package tech.pegasys.pantheon.tests.acceptance.dsl.condition.eea; import static org.assertj.core.api.Assertions.assertThat; +import static tech.pegasys.pantheon.tests.acceptance.dsl.WaitUtils.waitFor; import tech.pegasys.pantheon.tests.acceptance.dsl.condition.Condition; import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node; @@ -30,7 +31,10 @@ public class ExpectSuccessfulEeaGetTransactionReceipt implements Condition { @Override public void verify(final Node node) { - final PrivateTransactionReceipt response = node.execute(transaction); - assertThat(response.getContractAddress()).isNotEqualTo("0x"); + waitFor( + () -> { + final PrivateTransactionReceipt response = node.execute(transaction); + assertThat(response.getContractAddress()).isNotEqualTo("0x"); + }); } } diff --git a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/EthSignerClient.java b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/EthSignerClient.java new file mode 100644 index 0000000000..f796b9d3db --- /dev/null +++ b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/EthSignerClient.java @@ -0,0 +1,107 @@ +/* + * 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.tests.acceptance.dsl.ethsigner; + +import java.io.IOException; +import java.math.BigInteger; +import java.net.URI; +import java.util.Collections; +import java.util.List; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.web3j.protocol.Web3jService; +import org.web3j.protocol.core.Request; +import org.web3j.protocol.core.methods.request.Transaction; +import org.web3j.protocol.core.methods.response.EthSendTransaction; +import org.web3j.protocol.eea.Eea; +import org.web3j.protocol.http.HttpService; + +public class EthSignerClient { + private static final Logger LOG = LogManager.getLogger(); + private final Web3jService web3jService; + private final Eea web3j; + private final String from; + + public EthSignerClient(final URI ethSignerUri) throws IOException { + this.web3jService = new HttpService(ethSignerUri.toString()); + this.web3j = Eea.build(web3jService); + this.from = resolveFrom(ethSignerUri); + } + + private String resolveFrom(final URI ethSignerUri) throws IOException { + final List accounts; + try { + accounts = ethAccounts(); + return accounts.get(0); + } catch (IOException e) { + LOG.info("Failed to connect to EthSigner at {}", ethSignerUri); + throw e; + } catch (Exception e) { + LOG.info("Falling back to signing with node key"); + } + return null; + } + + public List ethAccounts() throws IOException { + return web3j.ethAccounts().send().getAccounts(); + } + + public String ethSendTransaction( + final String to, + final BigInteger gas, + final BigInteger gasPrice, + final BigInteger value, + final String data, + final BigInteger nonce) + throws IOException { + return web3j + .ethSendTransaction(new Transaction(from, nonce, gasPrice, gas, to, value, data)) + .send() + .getTransactionHash(); + } + + public String eeaSendTransaction( + final String to, + final BigInteger gas, + final BigInteger gasPrice, + final String data, + final BigInteger nonce, + final String privateFrom, + final List privateFor, + final String restriction) + throws IOException { + + final PrivateTransactionRequest transaction = + new PrivateTransactionRequest( + from, + nonce, + gasPrice, + gas, + to, + BigInteger.ZERO, + data, + privateFrom, + privateFor, + restriction); + + // temporary until implemented in web3j + return new Request<>( + "eea_sendTransaction", + Collections.singletonList(transaction), + web3jService, + EthSendTransaction.class) + .send() + .getTransactionHash(); + } +} diff --git a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/EthSignerClientTest.java b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/EthSignerClientTest.java new file mode 100644 index 0000000000..2a41f4566c --- /dev/null +++ b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/EthSignerClientTest.java @@ -0,0 +1,122 @@ +/* + * 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.tests.acceptance.dsl.ethsigner; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.Assert.assertEquals; + +import tech.pegasys.pantheon.tests.acceptance.dsl.ethsigner.testutil.EthSignerTestHarness; +import tech.pegasys.pantheon.tests.acceptance.dsl.ethsigner.testutil.EthSignerTestHarnessFactory; + +import java.io.IOException; +import java.math.BigInteger; +import java.net.HttpURLConnection; +import java.net.InetSocketAddress; +import java.util.Collections; +import java.util.List; + +import com.sun.net.httpserver.HttpServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +public class EthSignerClientTest { + @ClassRule public static final TemporaryFolder folder = new TemporaryFolder(); + private static final String MOCK_RESPONSE = "mock_transaction_hash"; + private static final String MOCK_SEND_TRANSACTION_RESPONSE = + "{\n" + + " \"id\":67,\n" + + " \"jsonrpc\":\"2.0\",\n" + + " \"result\": \"" + + MOCK_RESPONSE + + "\"\n" + + "}"; + private static final String ENCLAVE_PUBLIC_KEY = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; + + private static EthSignerClient ethSignerClient; + + private static EthSignerTestHarness testHarness; + + // The downstream server EthSigner should proxy requests to + private static HttpServer mockServer; + + @BeforeClass + public static void setUpOnce() throws Exception { + folder.create(); + + testHarness = + EthSignerTestHarnessFactory.create( + folder.newFolder().toPath(), + "ethSignerKey--fe3b557e8fb62b89f4916b721be55ceb828dbd73.json", + 1111, + 8545, + 2018); + + ethSignerClient = new EthSignerClient(testHarness.getHttpListeningUrl()); + + mockServer = HttpServer.create(new InetSocketAddress(1111), 0); + mockServer.createContext( + "/", + exchange -> { + byte[] response = MOCK_SEND_TRANSACTION_RESPONSE.getBytes(UTF_8); + exchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, response.length); + exchange.getResponseBody().write(response); + exchange.close(); + }); + mockServer.start(); + } + + @Test + public void testEthAccounts() throws IOException { + final List accounts = ethSignerClient.ethAccounts(); + assertEquals(1, accounts.size()); + assertEquals("0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", accounts.get(0)); + } + + @Test + public void testEthSendTransaction() throws IOException { + final String response = + ethSignerClient.ethSendTransaction( + "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", + BigInteger.ZERO, + BigInteger.ZERO, + BigInteger.ZERO, + "", + BigInteger.ZERO); + + assertEquals(MOCK_RESPONSE, response); + } + + @Test + public void testEeaSendTransaction() throws IOException { + final String response = + ethSignerClient.eeaSendTransaction( + "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", + BigInteger.ZERO, + BigInteger.ZERO, + "", + BigInteger.ZERO, + ENCLAVE_PUBLIC_KEY, + Collections.emptyList(), + ""); + + assertEquals(MOCK_RESPONSE, response); + } + + @AfterClass + public static void bringDownOnce() { + mockServer.stop(0); + } +} diff --git a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/PrivateTransactionRequest.java b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/PrivateTransactionRequest.java new file mode 100644 index 0000000000..11ad8521cf --- /dev/null +++ b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/PrivateTransactionRequest.java @@ -0,0 +1,101 @@ +/* + * 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.tests.acceptance.dsl.ethsigner; + +import java.math.BigInteger; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonInclude; +import org.web3j.utils.Numeric; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class PrivateTransactionRequest { + + private final String from; + private final BigInteger nonce; + private final BigInteger gasPrice; + private final BigInteger gas; + private final String to; + private final BigInteger value; + private final String data; + private final String privateFrom; + private final List privateFor; + private final String restriction; + + public PrivateTransactionRequest( + final String from, + final BigInteger nonce, + final BigInteger gasPrice, + final BigInteger gasLimit, + final String to, + final BigInteger value, + final String data, + final String privateFrom, + final List privateFor, + final String restriction) { + this.from = from; + this.to = to; + this.gas = gasLimit; + this.gasPrice = gasPrice; + this.value = value; + this.data = data == null ? null : Numeric.prependHexPrefix(data); + this.nonce = nonce; + this.privateFrom = privateFrom; + this.privateFor = privateFor; + this.restriction = restriction; + } + + public String getFrom() { + return from; + } + + public String getTo() { + return to; + } + + public String getGas() { + return convert(gas); + } + + public String getGasPrice() { + return convert(gasPrice); + } + + public String getValue() { + return convert(value); + } + + public String getData() { + return data; + } + + public String getNonce() { + return convert(nonce); + } + + private String convert(final BigInteger value) { + return value == null ? null : Numeric.encodeQuantity(value); + } + + public String getPrivateFrom() { + return privateFrom; + } + + public List getPrivateFor() { + return privateFor; + } + + public String getRestriction() { + return restriction; + } +} diff --git a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/testutil/EthSignerConfig.java b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/testutil/EthSignerConfig.java new file mode 100644 index 0000000000..34c89cae36 --- /dev/null +++ b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/testutil/EthSignerConfig.java @@ -0,0 +1,93 @@ +/* + * 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.tests.acceptance.dsl.ethsigner.testutil; + +import tech.pegasys.ethsigner.core.Config; +import tech.pegasys.ethsigner.core.signing.ChainIdProvider; + +import java.net.InetAddress; +import java.nio.file.Path; +import java.time.Duration; + +import org.apache.logging.log4j.Level; + +public class EthSignerConfig implements Config { + private final Level logLevel; + private final InetAddress downstreamHttpHost; + private final Integer downStreamHttpPort; + private Duration downstreamHttpRequestTimeout; + private final InetAddress httpListenHost; + private final Integer httpListenPort; + private final ChainIdProvider chainId; + private final Path dataDirectory; + + public EthSignerConfig( + final Level logLevel, + final InetAddress downstreamHttpHost, + final Integer downStreamHttpPort, + final Duration downstreamHttpRequestTimeout, + final InetAddress httpListenHost, + final Integer httpListenPort, + final ChainIdProvider chainId, + final Path dataDirectory) { + + this.logLevel = logLevel; + this.downstreamHttpHost = downstreamHttpHost; + this.downStreamHttpPort = downStreamHttpPort; + this.downstreamHttpRequestTimeout = downstreamHttpRequestTimeout; + this.httpListenHost = httpListenHost; + this.httpListenPort = httpListenPort; + this.chainId = chainId; + this.dataDirectory = dataDirectory; + } + + @Override + public Level getLogLevel() { + return logLevel; + } + + @Override + public InetAddress getDownstreamHttpHost() { + return downstreamHttpHost; + } + + @Override + public Integer getDownstreamHttpPort() { + return downStreamHttpPort; + } + + @Override + public Duration getDownstreamHttpRequestTimeout() { + return downstreamHttpRequestTimeout; + } + + @Override + public InetAddress getHttpListenHost() { + return httpListenHost; + } + + @Override + public Integer getHttpListenPort() { + return httpListenPort; + } + + @Override + public ChainIdProvider getChainId() { + return chainId; + } + + @Override + public Path getDataPath() { + return dataDirectory; + } +} diff --git a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/testutil/EthSignerTestHarness.java b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/testutil/EthSignerTestHarness.java new file mode 100644 index 0000000000..15923deb08 --- /dev/null +++ b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/testutil/EthSignerTestHarness.java @@ -0,0 +1,28 @@ +/* + * 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.tests.acceptance.dsl.ethsigner.testutil; + +import java.net.URI; + +public class EthSignerTestHarness { + private final EthSignerConfig config; + + public EthSignerTestHarness(final EthSignerConfig config) { + this.config = config; + } + + public URI getHttpListeningUrl() { + return URI.create( + "http://" + config.getHttpListenHost().getHostAddress() + ":" + config.getHttpListenPort()); + } +} diff --git a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/testutil/EthSignerTestHarnessFactory.java b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/testutil/EthSignerTestHarnessFactory.java new file mode 100644 index 0000000000..f70890481b --- /dev/null +++ b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/ethsigner/testutil/EthSignerTestHarnessFactory.java @@ -0,0 +1,84 @@ +/* + * 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.tests.acceptance.dsl.ethsigner.testutil; + +import static net.consensys.cava.io.file.Files.copyResource; +import static tech.pegasys.pantheon.tests.acceptance.dsl.WaitUtils.waitFor; + +import tech.pegasys.ethsigner.core.EthSigner; +import tech.pegasys.ethsigner.core.signing.ConfigurationChainId; +import tech.pegasys.ethsigner.signer.filebased.CredentialTransactionSigner; + +import java.io.IOException; +import java.net.InetAddress; +import java.nio.file.Path; +import java.time.Duration; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.web3j.crypto.CipherException; +import org.web3j.crypto.WalletUtils; + +public class EthSignerTestHarnessFactory { + + private static final Logger LOG = LogManager.getLogger(); + private static final String HOST = "127.0.0.1"; + + public static EthSignerTestHarness create( + final Path tempDir, + final String keyPath, + final Integer pantheonPort, + final Integer ethsignerPort, + final long chainId) + throws IOException, CipherException { + + final Path keyFilePath = copyResource(keyPath, tempDir.resolve(keyPath)); + + final EthSignerConfig config = + new EthSignerConfig( + Level.DEBUG, + InetAddress.getByName(HOST), + pantheonPort, + Duration.ofSeconds(10), + InetAddress.getByName(HOST), + ethsignerPort, + new ConfigurationChainId(chainId), + tempDir); + + final EthSigner ethSigner = + new EthSigner( + config, + new CredentialTransactionSigner( + WalletUtils.loadCredentials("", keyFilePath.toAbsolutePath().toFile()))); + ethSigner.run(); + + final OkHttpClient client = new OkHttpClient.Builder().build(); + final Request request = + new Request.Builder() + .url("http://" + HOST + ":" + ethsignerPort + "/upcheck") + .get() + .build(); + + waitFor( + () -> { + client.newCall(request).execute(); + }); + + LOG.info("EthSigner port: {}", config.getHttpListenPort()); + + return new EthSignerTestHarness(config); + } +} diff --git a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/PantheonNode.java b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/PantheonNode.java index 452f745bf5..37c8a21b74 100644 --- a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/PantheonNode.java +++ b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/PantheonNode.java @@ -250,6 +250,14 @@ public class PantheonNode implements NodeConfiguration, RunnableNode, AutoClosea } } + public Optional getJsonRpcSocketPort() { + if (isWebSocketsRpcEnabled()) { + return Optional.of(Integer.valueOf(portsProperties.getProperty("json-rpc"))); + } else { + return Optional.empty(); + } + } + @Override public String getHostName() { return LOCALHOST; diff --git a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/transaction/eea/PrivateTransactionBuilder.java b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/transaction/eea/PrivateTransactionBuilder.java index 91c521a085..1e28142d69 100644 --- a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/transaction/eea/PrivateTransactionBuilder.java +++ b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/transaction/eea/PrivateTransactionBuilder.java @@ -27,7 +27,7 @@ import java.util.Optional; public class PrivateTransactionBuilder { - private static BytesValue EVENT_EMITTER_CONSTRUCTOR = + public static BytesValue EVENT_EMITTER_CONSTRUCTOR = BytesValue.fromHexString( "0x608060405234801561001057600080fd5b5060008054600160a06" + "0020a03191633179055610199806100326000396000f3fe6080" diff --git a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/web3j/privacy/EthSignerAcceptanceTest.java b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/web3j/privacy/EthSignerAcceptanceTest.java new file mode 100644 index 0000000000..2f484b4339 --- /dev/null +++ b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/web3j/privacy/EthSignerAcceptanceTest.java @@ -0,0 +1,81 @@ +/* + * 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.tests.web3j.privacy; + +import static tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eea.PrivateTransactionBuilder.EVENT_EMITTER_CONSTRUCTOR; +import static tech.pegasys.pantheon.tests.web3j.privacy.PrivacyGroup.generatePrivacyGroup; + +import tech.pegasys.pantheon.ethereum.core.Address; +import tech.pegasys.pantheon.tests.acceptance.dsl.ethsigner.EthSignerClient; +import tech.pegasys.pantheon.tests.acceptance.dsl.ethsigner.testutil.EthSignerTestHarness; +import tech.pegasys.pantheon.tests.acceptance.dsl.ethsigner.testutil.EthSignerTestHarnessFactory; +import tech.pegasys.pantheon.tests.acceptance.dsl.privacy.PrivacyAcceptanceTestBase; +import tech.pegasys.pantheon.tests.acceptance.dsl.privacy.PrivacyNet; +import tech.pegasys.pantheon.util.bytes.BytesValue; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.Collections; + +import org.junit.Before; +import org.junit.Test; + +public class EthSignerAcceptanceTest extends PrivacyAcceptanceTestBase { + private PrivacyNet privacyNet; + + private EthSignerClient ethSignerClient; + + @Before + public void setUp() throws Exception { + privacyNet = + PrivacyNet.builder(privacy, privacyPantheon, cluster, false).addMinerNode("Alice").build(); + privacyNet.startPrivacyNet(); + + final EthSignerTestHarness ethsigner = + EthSignerTestHarnessFactory.create( + privacy.newFolder().toPath(), + "ethSignerKey--fe3b557e8fb62b89f4916b721be55ceb828dbd73.json", + privacyNet.getNode("Alice").getJsonRpcSocketPort().orElse(8545), + 23606, + 2018); + ethSignerClient = new EthSignerClient(ethsigner.getHttpListeningUrl()); + } + + @Test + public void privateSmartContractMustDeploy() throws IOException { + final BytesValue privacyGroupId = generatePrivacyGroup(privacyNet, "Alice"); + final long nonce = privacyNet.getNode("Alice").nextNonce(privacyGroupId); + + final String transactionHash = + ethSignerClient.eeaSendTransaction( + null, + BigInteger.valueOf(63992), + BigInteger.valueOf(1000), + EVENT_EMITTER_CONSTRUCTOR.toString(), + BigInteger.valueOf(nonce), + privacyNet.getEnclave("Alice").getPublicKeys().get(0), + Collections.emptyList(), + "restricted"); + + privacyNet.getNode("Alice").verify(eea.expectSuccessfulTransactionReceipt(transactionHash)); + + final String expectedContractAddress = + Address.privateContractAddress( + privacyNet.getNode("Alice").getAddress(), nonce, privacyGroupId) + .toString(); + + privateTransactionVerifier + .validPrivateContractDeployed(expectedContractAddress) + .verify(privacyNet.getNode("Alice"), transactionHash); + } +} diff --git a/gradle/versions.gradle b/gradle/versions.gradle index ed64d8dd21..f76d22c312 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -71,7 +71,7 @@ dependencyManagement { dependency 'org.jupnp:org.jupnp:2.5.2' dependency 'org.jupnp:org.jupnp.support:2.5.2' - + dependency 'org.mockito:mockito-core:2.28.2' dependency 'org.openjdk.jmh:jmh-core:1.21' @@ -80,15 +80,20 @@ dependencyManagement { dependency 'org.rocksdb:rocksdbjni:5.15.10' dependency 'org.slf4j:slf4j-log4j12:1.7.26' - + dependency 'org.springframework.security:spring-security-crypto:5.1.5.RELEASE' dependency 'org.web3j:abi:4.3.1' dependency 'org.web3j:core:4.3.1' dependency 'org.web3j:crypto:4.3.1' + dependency 'org.web3j:eea:4.3.1' dependency 'org.xerial.snappy:snappy-java:1.1.7.3' + dependency "tech.pegasys.ethsigner.internal:core:0.2.0" + dependency "tech.pegasys.ethsigner.internal:file-based:0.2.0" + dependency "tech.pegasys.ethsigner.internal:signing-api:0.2.0" + dependency "tech.pegasys.pantheon:plugin-api:1.2.2" } } diff --git a/testutil/build.gradle b/testutil/build.gradle index b72215da56..0ed5caaadb 100644 --- a/testutil/build.gradle +++ b/testutil/build.gradle @@ -31,4 +31,5 @@ dependencies { implementation 'com.squareup.okhttp3:okhttp' implementation 'net.consensys:orion' implementation 'org.mockito:mockito-core' + implementation 'org.web3j:core' } diff --git a/testutil/src/main/resources/ethSignerKey--fe3b557e8fb62b89f4916b721be55ceb828dbd73.json b/testutil/src/main/resources/ethSignerKey--fe3b557e8fb62b89f4916b721be55ceb828dbd73.json new file mode 100644 index 0000000000..df41089342 --- /dev/null +++ b/testutil/src/main/resources/ethSignerKey--fe3b557e8fb62b89f4916b721be55ceb828dbd73.json @@ -0,0 +1 @@ +{"address":"fe3b557e8fb62b89f4916b721be55ceb828dbd73","id":"004bac44-2955-40bf-8b1f-5376f428644f","version":3,"crypto":{"cipher":"aes-128-ctr","ciphertext":"28e23ffb25d1ef6a665a5a61866f353c2640b2ec55bd080f557ac4da8c8ba1d1","cipherparams":{"iv":"07bf8e210d7fbb5c4731ac15388a7939"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":4096,"p":6,"r":8,"salt":"8d454299a7ac29cbcd8817a8d1f12723592421d3e0a8bc56aff4719bf78bcec9"},"mac":"9073b2a8f454b0942b9350da96b1431e15edfdddb796ece0ab3fc6e14ca18190"}} \ No newline at end of file