Skip to content

Commit

Permalink
[PAN-2789] Add ethSigner acceptance test (PegaSysEng#1655)
Browse files Browse the repository at this point in the history
  • Loading branch information
iikirilov authored and MadelineMurray committed Aug 27, 2019
1 parent 47295f1 commit b023831
Show file tree
Hide file tree
Showing 14 changed files with 644 additions and 6 deletions.
5 changes: 4 additions & 1 deletion acceptance-tests/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -30,7 +31,10 @@ public ExpectSuccessfulEeaGetTransactionReceipt(

@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");
});
}
}
Original file line number Diff line number Diff line change
@@ -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<String> 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<String> 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<String> 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();
}
}
Original file line number Diff line number Diff line change
@@ -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<String> 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);
}
}
Original file line number Diff line number Diff line change
@@ -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<String> 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<String> 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<String> getPrivateFor() {
return privateFor;
}

public String getRestriction() {
return restriction;
}
}
Loading

0 comments on commit b023831

Please sign in to comment.