[PAN-2652] Refactor Privacy acceptance test and add Privacy Ibft test (#1483)

* Add IBFT2 Privacy Acceptance test

* Refactor eea conditions

* Refactor privacy test utils

* Refactor privacy tests

* Fix typo

Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
Ivaylo Kirilov 6 years ago committed by Eric Kellstrand
parent fc4f9917b7
commit e91ba1efea
  1. 19
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/condition/eea/EeaCondition.java
  2. 3
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/condition/eea/ExpectNoPrivateContractDeployedReceipt.java
  3. 37
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/condition/eea/ExpectNoValidPrivateContractEventsEmitted.java
  4. 5
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/condition/eea/ExpectNoValidPrivateContractValuesReturned.java
  5. 3
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/condition/eea/ExpectValidPrivateContractDeployedReceipt.java
  6. 3
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/condition/eea/ExpectValidPrivateContractEventsEmitted.java
  7. 3
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/condition/eea/ExpectValidPrivateContractValuesReturned.java
  8. 3
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/condition/eea/ExpectValidPrivateTransactionReceipt.java
  9. 4
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/condition/eea/GetValidPrivateTransactionReceipt.java
  10. 4
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/PantheonNode.java
  11. 4
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/factory/PantheonFactoryConfiguration.java
  12. 126
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/factory/PantheonNodeFactory.java
  13. 122
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/factory/PantheonNodeFactoryUtils.java
  14. 26
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/privacy/PrivacyAcceptanceTestBase.java
  15. 278
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/privacy/PrivacyNet.java
  16. 105
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/privacy/PrivacyNode.java
  17. 71
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/privacy/PrivacyPantheonFactoryConfiguration.java
  18. 53
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/privacy/PrivacyPantheonFactoryConfigurationBuilder.java
  19. 108
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/privacy/PrivacyPantheonNodeFactory.java
  20. 11
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/privacy/PrivateTransactionVerifier.java
  21. 119
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/web3j/privacy/DeployPrivateSmartContractAcceptanceTest.java
  22. 297
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/web3j/privacy/EventEmitterHarness.java
  23. 134
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/web3j/privacy/IbftPrivacyClusterAcceptanceTest.java
  24. 507
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/web3j/privacy/PrivacyClusterAcceptanceTest.java
  25. 31
      pantheon/src/main/java/tech/pegasys/pantheon/controller/KeyPairUtil.java
  26. 44
      testutil/src/main/java/tech/pegasys/orion/testutil/OrionKeyGenerator.java
  27. 58
      testutil/src/main/java/tech/pegasys/orion/testutil/OrionTestHarnessFactory.java

@ -0,0 +1,19 @@
/*
* 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.condition.eea;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode;
public interface EeaCondition {
void verify(PantheonNode node, String transactionHash);
}

@ -10,7 +10,7 @@
* 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.privacy;
package tech.pegasys.pantheon.tests.acceptance.dsl.condition.eea;
import static org.junit.Assert.assertNull;
@ -25,6 +25,7 @@ public class ExpectNoPrivateContractDeployedReceipt extends GetValidPrivateTrans
super(eea, transactions);
}
@Override
public void verify(final PantheonNode node, final String transactionHash) {
ResponseTypes.PrivateTransactionReceipt privateTxReceipt =
getPrivateTransactionReceipt(node, transactionHash);

@ -0,0 +1,37 @@
/*
* 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.condition.eea;
import static junit.framework.TestCase.assertTrue;
import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Eea;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transactions;
public class ExpectNoValidPrivateContractEventsEmitted extends GetValidPrivateTransactionReceipt {
public ExpectNoValidPrivateContractEventsEmitted(final Eea eea, final Transactions transactions) {
super(eea, transactions);
}
@Override
public void verify(final PantheonNode node, final String transactionHash) {
ResponseTypes.PrivateTransactionReceipt privateTxReceipt =
getPrivateTransactionReceipt(node, transactionHash);
if (privateTxReceipt.getLogs() != null) {
assertTrue(privateTxReceipt.getLogs().isEmpty());
}
}
}

@ -10,7 +10,7 @@
* 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.privacy;
package tech.pegasys.pantheon.tests.acceptance.dsl.condition.eea;
import static org.junit.Assert.assertEquals;
@ -26,10 +26,13 @@ public class ExpectNoValidPrivateContractValuesReturned extends GetValidPrivateT
super(eea, transactions);
}
@Override
public void verify(final PantheonNode node, final String transactionHash) {
ResponseTypes.PrivateTransactionReceipt privateTxReceipt =
getPrivateTransactionReceipt(node, transactionHash);
if (privateTxReceipt.getOutput() != null) {
assertEquals("0x", privateTxReceipt.getOutput());
}
}
}

@ -10,7 +10,7 @@
* 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.privacy;
package tech.pegasys.pantheon.tests.acceptance.dsl.condition.eea;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
@ -30,6 +30,7 @@ public class ExpectValidPrivateContractDeployedReceipt extends GetValidPrivateTr
this.contractAddress = contractAddress;
}
@Override
public void verify(final PantheonNode node, final String transactionHash) {
ResponseTypes.PrivateTransactionReceipt privateTxReceipt =
getPrivateTransactionReceipt(node, transactionHash);

@ -10,7 +10,7 @@
* 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.privacy;
package tech.pegasys.pantheon.tests.acceptance.dsl.condition.eea;
import static org.junit.Assert.assertEquals;
@ -32,6 +32,7 @@ public class ExpectValidPrivateContractEventsEmitted extends GetValidPrivateTran
this.eventValue = eventValue;
}
@Override
public void verify(final PantheonNode node, final String transactionHash) {
ResponseTypes.PrivateTransactionReceipt privateTxReceipt =
getPrivateTransactionReceipt(node, transactionHash);

@ -10,7 +10,7 @@
* 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.privacy;
package tech.pegasys.pantheon.tests.acceptance.dsl.condition.eea;
import static org.junit.Assert.assertEquals;
@ -33,6 +33,7 @@ public class ExpectValidPrivateContractValuesReturned extends GetValidPrivateTra
this.returnValue = returnValue;
}
@Override
public void verify(final PantheonNode node, final String transactionHash) {
ResponseTypes.PrivateTransactionReceipt privateTxReceipt =
getPrivateTransactionReceipt(node, transactionHash);

@ -10,7 +10,7 @@
* 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.privacy;
package tech.pegasys.pantheon.tests.acceptance.dsl.condition.eea;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNotNull;
@ -26,6 +26,7 @@ public class ExpectValidPrivateTransactionReceipt extends GetValidPrivateTransac
super(eea, transactions);
}
@Override
public void verify(final PantheonNode node, final String transactionHash) {
ResponseTypes.PrivateTransactionReceipt privateTxReceipt =
getPrivateTransactionReceipt(node, transactionHash);

@ -10,7 +10,7 @@
* 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.privacy;
package tech.pegasys.pantheon.tests.acceptance.dsl.condition.eea;
import static tech.pegasys.pantheon.tests.acceptance.dsl.WaitUtils.waitFor;
@ -19,7 +19,7 @@ import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transactions;
public abstract class GetValidPrivateTransactionReceipt {
public abstract class GetValidPrivateTransactionReceipt implements EeaCondition {
private Eea eea;
private Transactions transactions;

@ -409,6 +409,10 @@ public class PantheonNode implements NodeConfiguration, RunnableNode, AutoClosea
return Util.publicKeyToAddress(keyPair.getPublicKey());
}
public KeyPair keyPair() {
return keyPair;
}
public Path homeDirectory() {
return homeDirectory;
}

@ -23,7 +23,7 @@ import tech.pegasys.pantheon.tests.acceptance.dsl.node.GenesisConfigProvider;
import java.util.List;
import java.util.Optional;
class PantheonFactoryConfiguration {
public class PantheonFactoryConfiguration {
private final String name;
private final MiningParameters miningParameters;
@ -41,7 +41,7 @@ class PantheonFactoryConfiguration {
private final List<String> plugins;
private final List<String> extraCLIOptions;
PantheonFactoryConfiguration(
public PantheonFactoryConfiguration(
final String name,
final MiningParameters miningParameters,
final PrivacyParameters privacyParameters,

@ -13,38 +13,19 @@
package tech.pegasys.pantheon.tests.acceptance.dsl.node.factory;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;
import static tech.pegasys.pantheon.consensus.clique.jsonrpc.CliqueRpcApis.CLIQUE;
import static tech.pegasys.pantheon.consensus.ibft.jsonrpc.IbftRpcApis.IBFT;
import tech.pegasys.pantheon.consensus.clique.CliqueExtraData;
import tech.pegasys.pantheon.consensus.ibft.IbftExtraData;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.PrivacyParameters;
import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration;
import tech.pegasys.pantheon.ethereum.jsonrpc.RpcApi;
import tech.pegasys.pantheon.ethereum.jsonrpc.RpcApis;
import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.WebSocketConfiguration;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.GenesisConfigProvider;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.RunnableNode;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import com.google.common.io.Resources;
public class PantheonNodeFactory {
public class PantheonNodeFactory extends PantheonNodeFactoryUtils {
PantheonNode create(final PantheonFactoryConfiguration config) throws IOException {
return new PantheonNode(
@ -75,33 +56,6 @@ public class PantheonNodeFactory {
.build());
}
public PantheonNode createPrivateTransactionEnabledMinerNode(
final String name, final PrivacyParameters privacyParameters, final String keyFilePath)
throws IOException {
return create(
new PantheonFactoryConfigurationBuilder()
.name(name)
.miningEnabled()
.jsonRpcEnabled()
.keyFilePath(keyFilePath)
.enablePrivateTransactions(privacyParameters)
.webSocketEnabled()
.build());
}
public PantheonNode createPrivateTransactionEnabledNode(
final String name, final PrivacyParameters privacyParameters, final String keyFilePath)
throws IOException {
return create(
new PantheonFactoryConfigurationBuilder()
.name(name)
.jsonRpcEnabled()
.keyFilePath(keyFilePath)
.enablePrivateTransactions(privacyParameters)
.webSocketEnabled()
.build());
}
public PantheonNode createArchiveNode(final String name) throws IOException {
return create(
new PantheonFactoryConfigurationBuilder()
@ -301,82 +255,4 @@ public class PantheonNodeFactory {
asList(validators), nodes, this::createIbftGenesisConfig))
.build());
}
private Optional<String> createCliqueGenesisConfig(
final Collection<? extends RunnableNode> validators) {
final String template = readGenesisFile("/clique/clique.json");
return updateGenesisExtraData(
validators, template, CliqueExtraData::createGenesisExtraDataString);
}
private Optional<String> createIbftGenesisConfig(
final Collection<? extends RunnableNode> validators) {
final String template = readGenesisFile("/ibft/ibft.json");
return updateGenesisExtraData(
validators, template, IbftExtraData::createGenesisExtraDataString);
}
private Optional<String> updateGenesisExtraData(
final Collection<? extends RunnableNode> validators,
final String genesisTemplate,
final Function<List<Address>, String> extraDataCreator) {
final List<Address> addresses =
validators.stream().map(RunnableNode::getAddress).collect(toList());
final String extraDataString = extraDataCreator.apply(addresses);
final String genesis = genesisTemplate.replaceAll("%extraData%", extraDataString);
return Optional.of(genesis);
}
private String readGenesisFile(final String filepath) {
try {
final URI uri = this.getClass().getResource(filepath).toURI();
return Resources.toString(uri.toURL(), Charset.defaultCharset());
} catch (final URISyntaxException | IOException e) {
throw new IllegalStateException("Unable to get test genesis config " + filepath);
}
}
private Optional<String> createGenesisConfigForValidators(
final Collection<String> validators,
final Collection<? extends RunnableNode> pantheonNodes,
final GenesisConfigProvider genesisConfigProvider) {
final List<RunnableNode> nodes =
pantheonNodes.stream().filter(n -> validators.contains(n.getName())).collect(toList());
return genesisConfigProvider.createGenesisConfig(nodes);
}
private JsonRpcConfiguration createJsonRpcConfigWithClique() {
return createJsonRpcConfigWithRpcApiEnabled(CLIQUE);
}
private JsonRpcConfiguration createJsonRpcConfigWithIbft() {
return createJsonRpcConfigWithRpcApiEnabled(IBFT);
}
private JsonRpcConfiguration createJsonRpcEnabledConfig() {
final JsonRpcConfiguration config = JsonRpcConfiguration.createDefault();
config.setEnabled(true);
config.setPort(0);
config.setHostsWhitelist(singletonList("*"));
return config;
}
private WebSocketConfiguration createWebSocketEnabledConfig() {
final WebSocketConfiguration config = WebSocketConfiguration.createDefault();
config.setEnabled(true);
config.setPort(0);
return config;
}
private JsonRpcConfiguration jsonRpcConfigWithAdmin() {
return createJsonRpcConfigWithRpcApiEnabled(RpcApis.ADMIN);
}
private JsonRpcConfiguration createJsonRpcConfigWithRpcApiEnabled(final RpcApi... rpcApi) {
final JsonRpcConfiguration jsonRpcConfig = createJsonRpcEnabledConfig();
final List<RpcApi> rpcApis = new ArrayList<>(jsonRpcConfig.getRpcApis());
rpcApis.addAll(Arrays.asList(rpcApi));
jsonRpcConfig.setRpcApis(rpcApis);
return jsonRpcConfig;
}
}

@ -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.node.factory;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;
import static tech.pegasys.pantheon.consensus.clique.jsonrpc.CliqueRpcApis.CLIQUE;
import static tech.pegasys.pantheon.consensus.ibft.jsonrpc.IbftRpcApis.IBFT;
import tech.pegasys.pantheon.consensus.clique.CliqueExtraData;
import tech.pegasys.pantheon.consensus.ibft.IbftExtraData;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration;
import tech.pegasys.pantheon.ethereum.jsonrpc.RpcApi;
import tech.pegasys.pantheon.ethereum.jsonrpc.RpcApis;
import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.WebSocketConfiguration;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.GenesisConfigProvider;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.RunnableNode;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import com.google.common.io.Resources;
public class PantheonNodeFactoryUtils {
public Optional<String> createCliqueGenesisConfig(
final Collection<? extends RunnableNode> validators) {
final String template = readGenesisFile("/clique/clique.json");
return updateGenesisExtraData(
validators, template, CliqueExtraData::createGenesisExtraDataString);
}
public Optional<String> createIbftGenesisConfig(
final Collection<? extends RunnableNode> validators) {
final String template = readGenesisFile("/ibft/ibft.json");
return updateGenesisExtraData(
validators, template, IbftExtraData::createGenesisExtraDataString);
}
public Optional<String> updateGenesisExtraData(
final Collection<? extends RunnableNode> validators,
final String genesisTemplate,
final Function<List<Address>, String> extraDataCreator) {
final List<Address> addresses =
validators.stream().map(RunnableNode::getAddress).collect(toList());
final String extraDataString = extraDataCreator.apply(addresses);
final String genesis = genesisTemplate.replaceAll("%extraData%", extraDataString);
return Optional.of(genesis);
}
public String readGenesisFile(final String filepath) {
try {
final URI uri = this.getClass().getResource(filepath).toURI();
return Resources.toString(uri.toURL(), Charset.defaultCharset());
} catch (final URISyntaxException | IOException e) {
throw new IllegalStateException("Unable to get test genesis config " + filepath);
}
}
public Optional<String> createGenesisConfigForValidators(
final Collection<String> validators,
final Collection<? extends RunnableNode> pantheonNodes,
final GenesisConfigProvider genesisConfigProvider) {
final List<RunnableNode> nodes =
pantheonNodes.stream().filter(n -> validators.contains(n.getName())).collect(toList());
return genesisConfigProvider.createGenesisConfig(nodes);
}
public JsonRpcConfiguration createJsonRpcConfigWithClique() {
return createJsonRpcConfigWithRpcApiEnabled(CLIQUE);
}
public JsonRpcConfiguration createJsonRpcConfigWithIbft() {
return createJsonRpcConfigWithRpcApiEnabled(IBFT);
}
public JsonRpcConfiguration createJsonRpcEnabledConfig() {
final JsonRpcConfiguration config = JsonRpcConfiguration.createDefault();
config.setEnabled(true);
config.setPort(0);
config.setHostsWhitelist(singletonList("*"));
return config;
}
public WebSocketConfiguration createWebSocketEnabledConfig() {
final WebSocketConfiguration config = WebSocketConfiguration.createDefault();
config.setEnabled(true);
config.setPort(0);
return config;
}
public JsonRpcConfiguration jsonRpcConfigWithAdmin() {
return createJsonRpcConfigWithRpcApiEnabled(RpcApis.ADMIN);
}
public JsonRpcConfiguration createJsonRpcConfigWithRpcApiEnabled(final RpcApi... rpcApi) {
final JsonRpcConfiguration jsonRpcConfig = createJsonRpcEnabledConfig();
final List<RpcApi> rpcApis = new ArrayList<>(jsonRpcConfig.getRpcApis());
rpcApis.addAll(Arrays.asList(rpcApi));
jsonRpcConfig.setRpcApis(rpcApis);
return jsonRpcConfig;
}
}

@ -12,48 +12,30 @@
*/
package tech.pegasys.pantheon.tests.acceptance.dsl.privacy;
import tech.pegasys.orion.testutil.OrionTestHarness;
import tech.pegasys.orion.testutil.OrionTestHarnessFactory;
import tech.pegasys.pantheon.ethereum.core.PrivacyParameters;
import tech.pegasys.pantheon.tests.acceptance.dsl.AcceptanceTestBase;
import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Eea;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eea.EeaTransactions;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eea.PrivateTransactionBuilder;
import java.io.IOException;
import org.junit.ClassRule;
import org.junit.rules.TemporaryFolder;
public class PrivateAcceptanceTestBase extends AcceptanceTestBase {
public class PrivacyAcceptanceTestBase extends AcceptanceTestBase {
@ClassRule public static final TemporaryFolder privacy = new TemporaryFolder();
protected final Eea eea;
protected final PrivateTransactions privateTransactions;
protected static PrivateTransactionBuilder.Builder privateTransactionBuilder;
protected final PrivateTransactionVerifier privateTransactionVerifier;
protected final PrivacyPantheonNodeFactory privacyPantheon;
public PrivateAcceptanceTestBase() {
public PrivacyAcceptanceTestBase() {
final EeaTransactions eeaTransactions = new EeaTransactions();
privateTransactions = new PrivateTransactions();
eea = new Eea(eeaTransactions);
privateTransactionBuilder = PrivateTransactionBuilder.builder();
privateTransactionVerifier = new PrivateTransactionVerifier(eea, transactions);
}
protected static OrionTestHarness createEnclave(
final String pubKey, final String privKey, final String... othernode) throws Exception {
return OrionTestHarnessFactory.create(privacy.newFolder().toPath(), pubKey, privKey, othernode);
}
protected static PrivacyParameters getPrivacyParameters(final OrionTestHarness testHarness)
throws IOException {
return new PrivacyParameters.Builder()
.setEnabled(true)
.setEnclaveUrl(testHarness.clientUrl())
.setEnclavePublicKeyUsingFile(testHarness.getConfig().publicKeys().get(0).toFile())
.setDataDir(privacy.newFolder().toPath())
.build();
privacyPantheon = new PrivacyPantheonNodeFactory();
}
}

@ -0,0 +1,278 @@
/*
* 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.privacy;
import tech.pegasys.orion.testutil.OrionTestHarness;
import tech.pegasys.orion.testutil.OrionTestHarnessFactory;
import tech.pegasys.pantheon.ethereum.core.PrivacyParameters;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.cluster.Cluster;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import com.google.common.base.Preconditions;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.rules.TemporaryFolder;
public class PrivacyNet {
private static final Logger LOG = LogManager.getLogger();
private static final String PANTHEON_KEYPAIR_NODE_1 = "key";
private static final String PANTHEON_KEYPAIR_NODE_2 = "key1";
private static final String PANTHEON_KEYPAIR_NODE_3 = "key2";
private static final Map<String, String> KNOWN_PANTHEON_KEYPAIRS = new HashMap<>();
private final TemporaryFolder temporaryFolder;
private Cluster cluster;
private Map<String, PrivacyNode> nodes;
static {
KNOWN_PANTHEON_KEYPAIRS.put("Alice", PANTHEON_KEYPAIR_NODE_1);
KNOWN_PANTHEON_KEYPAIRS.put("Bob", PANTHEON_KEYPAIR_NODE_2);
KNOWN_PANTHEON_KEYPAIRS.put("Charlie", PANTHEON_KEYPAIR_NODE_3);
}
private PrivacyNet(
final TemporaryFolder temporaryFolder,
final Map<String, PrivacyNode> privacyNodes,
final Cluster cluster) {
this.temporaryFolder = temporaryFolder;
this.nodes = privacyNodes;
this.cluster = cluster;
}
public static PrivacyNet.Builder builder(
final TemporaryFolder temporaryFolder,
final PrivacyPantheonNodeFactory pantheonNodeFactory,
final Cluster cluster,
final boolean ibft) {
return new Builder(temporaryFolder, pantheonNodeFactory, cluster, ibft);
}
public Map<String, PrivacyNode> getNodes() {
return nodes;
}
public PantheonNode getPantheon(final String name) {
return nodes.get(name);
}
public OrionTestHarness getEnclave(final String name) {
return nodes.get(name).orion;
}
public void startPrivacyNet() {
if (nodes == null)
throw new IllegalStateException(
"Cannot start network nodes. init method was never called to initialize the nodes");
cluster.start(nodes.values().toArray(new PrivacyNode[0]));
verifyAllOrionNetworkConnections();
}
public void stopPrivacyNet() {
try {
cluster.stop();
} catch (RuntimeException e) {
LOG.error("Error stopping Pantheon nodes. Logging and continuing.", e);
}
try {
stopOrionNodes();
} catch (RuntimeException e) {
LOG.error("Error stopping Orion nodes. Logging and continuing.", e);
}
}
private void stopOrionNodes() {
if (nodes == null) return; // Never started
for (PrivacyNode node : nodes.values()) {
try {
node.orion.getOrion().stop();
} catch (RuntimeException e) {
LOG.error(
String.format(
"Error stopping Orion node %s. Logging and continuing to shutdown other nodes.",
node.orion.nodeUrl()),
e);
}
}
}
/** Verify that each Orion node has connected to every other Orion */
public void verifyAllOrionNetworkConnections() {
PrivacyNode[] nodeList = nodes.values().toArray(new PrivacyNode[0]);
for (int i = 0; i < nodeList.length; i++) {
for (int j = i + 1; j < nodeList.length; j++) {
nodeList[i].testOrionConnection(nodeList[j]);
}
for (int j = i + 2; j < nodeList.length; j = j + 2) {
nodeList[i].testOrionConnection(nodeList[j]);
}
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(String.format("temporaryFolder = %s\n", temporaryFolder.getRoot()));
for (PrivacyNode privacyNode : nodes.values()) {
sb.append(String.format("Pantheon Node Name = %s\n", privacyNode.getName()));
sb.append(String.format("Pantheon Address = %s\n", privacyNode.getAddress()));
sb.append(
String.format("Pantheon Private Key = %s\n", privacyNode.keyPair().getPrivateKey()));
sb.append(String.format("Pantheon Public Key = %s\n", privacyNode.keyPair().getPublicKey()));
sb.append(String.format("Orion Pub Key = %s\n", privacyNode.getOrionPubKeyBytes()));
sb.append(
String.format(
"Orion Pub Key Base64 = %s\n",
Base64.getEncoder()
.encodeToString(privacyNode.getOrionPubKeyBytes().extractArray())));
sb.append(String.format("Pantheon = %s\n", privacyNode));
sb.append(String.format("Orion Config = %s\n", privacyNode.orion.getConfig()));
sb.append(String.format("Orion Pub Key = %s\n", privacyNode.getOrionPubKeyBytes()));
}
return sb.toString();
}
public static class Builder {
private TemporaryFolder temporaryFolder;
private PrivacyPantheonNodeFactory pantheonNodeFactory;
private Cluster cluster;
private final boolean ibft;
private String otherOrionNode = null;
private Map<String, PrivacyNode> nodes;
private Builder(
final TemporaryFolder temporaryFolder,
final PrivacyPantheonNodeFactory pantheonNodeFactory,
final Cluster cluster,
final boolean ibft) {
this.temporaryFolder = temporaryFolder;
this.pantheonNodeFactory = pantheonNodeFactory;
this.cluster = cluster;
this.ibft = ibft;
}
public Builder addMinerNode(final String name) throws IOException {
return addNode(name, true);
}
public Builder addNode(final String name) throws IOException {
return addNode(name, false);
}
public Builder addNode(final String name, final Optional<String> keyPath) throws IOException {
return addNode(name, false, keyPath);
}
public Builder addNode(final String name, final boolean isMiningEnabled) throws IOException {
return addNode(name, isMiningEnabled, Optional.empty());
}
public Builder addNode(
final String name, final boolean isMiningEnabled, final Optional<String> keyPath)
throws IOException {
final PrivacyNode node = makeNode(name, isMiningEnabled, otherOrionNode, keyPath);
if (nodes == null) {
nodes = new HashMap<>();
otherOrionNode = node.orion.nodeUrl(); // All nodes use first added node for discovery
}
nodes.put(name, node);
return this;
}
public PrivacyNode makeNode(
final String name,
final boolean isMiningEnabled,
final String otherOrionNodes,
final Optional<String> orionKeyPath)
throws IOException {
final OrionTestHarness orion;
if (otherOrionNodes == null) {
// Need conditional because createEnclave will choke if passing in null
orion = createEnclave(temporaryFolder, orionKeyPath);
} else {
orion = createEnclave(temporaryFolder, orionKeyPath, otherOrionNodes);
}
final PrivacyNode node;
final String keyFilePath = KNOWN_PANTHEON_KEYPAIRS.get(name);
if (isMiningEnabled && !ibft) {
node =
pantheonNodeFactory.createPrivateTransactionEnabledMinerNode(
name, generatePrivacyParameters(orion), keyFilePath, orion);
} else if (!isMiningEnabled && !ibft) {
node =
pantheonNodeFactory.createPrivateTransactionEnabledNode(
name, generatePrivacyParameters(orion), keyFilePath, orion);
} else {
node =
pantheonNodeFactory.createIbftNodePrivacyEnabled(
name, generatePrivacyParameters(orion), keyFilePath, orion);
}
return node;
}
protected OrionTestHarness createEnclave(
final TemporaryFolder temporaryFolder,
final Optional<String> pubKeyPath,
final String... othernode)
throws IOException {
final Path tmpPath = temporaryFolder.newFolder().toPath();
final String orionPublicKeyFileName = pubKeyPath.orElse(provideNextKnownOrionKey());
final String orionPrivateKeyFileName = privaKeyPathFromPubKeyPath(orionPublicKeyFileName);
return OrionTestHarnessFactory.create(
tmpPath, orionPublicKeyFileName, orionPrivateKeyFileName, othernode);
}
private String privaKeyPathFromPubKeyPath(final String orionPublicKeyFileName) {
return orionPublicKeyFileName.substring(0, orionPublicKeyFileName.length() - 3) + "key";
}
private Integer nextKnownOrionKey = 0;
private String provideNextKnownOrionKey() {
if (nextKnownOrionKey < 4) {
return String.format("orion_key_%d.pub", nextKnownOrionKey++);
}
throw new RuntimeException("Limit of known nodes reached");
}
private PrivacyParameters generatePrivacyParameters(final OrionTestHarness testHarness)
throws IOException {
return new PrivacyParameters.Builder()
.setEnabled(true)
.setEnclaveUrl(testHarness.clientUrl())
.setEnclavePublicKeyUsingFile(testHarness.getConfig().publicKeys().get(0).toFile())
.setDataDir(temporaryFolder.newFolder().toPath())
.build();
}
public PrivacyNet build() {
Preconditions.checkNotNull(nodes);
return new PrivacyNet(temporaryFolder, nodes, cluster);
}
}
}

@ -0,0 +1,105 @@
/*
* 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.privacy;
import static java.nio.charset.StandardCharsets.UTF_8;
import static tech.pegasys.pantheon.tests.acceptance.dsl.WaitUtils.waitFor;
import tech.pegasys.orion.testutil.OrionTestHarness;
import tech.pegasys.pantheon.enclave.Enclave;
import tech.pegasys.pantheon.enclave.types.SendRequest;
import tech.pegasys.pantheon.ethereum.core.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.PrivacyParameters;
import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration;
import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.WebSocketConfiguration;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.metrics.prometheus.MetricsConfiguration;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.GenesisConfigProvider;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class PrivacyNode extends PantheonNode {
private static final Logger LOG = LogManager.getLogger();
public OrionTestHarness orion;
public PrivacyNode(
final String name,
final MiningParameters miningParameters,
final PrivacyParameters privacyParameters,
final JsonRpcConfiguration jsonRpcConfiguration,
final WebSocketConfiguration webSocketConfiguration,
final MetricsConfiguration metricsConfiguration,
final Optional<PermissioningConfiguration> permissioningConfiguration,
final Optional<String> keyfilePath,
final boolean devMode,
final GenesisConfigProvider genesisConfigProvider,
final boolean p2pEnabled,
final boolean discoveryEnabled,
final boolean bootnodeEligible,
final List<String> plugins,
final List<String> extraCLIOptions,
final OrionTestHarness orion)
throws IOException {
super(
name,
miningParameters,
privacyParameters,
jsonRpcConfiguration,
webSocketConfiguration,
metricsConfiguration,
permissioningConfiguration,
keyfilePath,
devMode,
genesisConfigProvider,
p2pEnabled,
discoveryEnabled,
bootnodeEligible,
plugins,
extraCLIOptions);
this.orion = orion;
}
public BytesValue getOrionPubKeyBytes() {
return BytesValue.wrap(orion.getPublicKeys().get(0).getBytes(UTF_8));
}
public void testOrionConnection(final PrivacyNode... otherNodes) {
LOG.info(
String.format(
"Testing Orion connectivity between %s (%s) and %s (%s)",
getName(),
orion.nodeUrl(),
Arrays.toString(Arrays.stream(otherNodes).map(PrivacyNode::getName).toArray()),
Arrays.toString(
Arrays.stream(otherNodes).map(node -> node.orion.nodeUrl()).toArray())));
Enclave orionEnclave = new Enclave(orion.clientUrl());
SendRequest sendRequest1 =
new SendRequest(
"SGVsbG8sIFdvcmxkIQ==",
orion.getPublicKeys().get(0),
Arrays.stream(otherNodes)
.map(node -> node.orion.getPublicKeys().get(0))
.collect(Collectors.toList()));
waitFor(() -> orionEnclave.send(sendRequest1));
}
}

@ -0,0 +1,71 @@
/*
* Copyright 2018 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.privacy;
import tech.pegasys.orion.testutil.OrionTestHarness;
import tech.pegasys.pantheon.ethereum.core.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.PrivacyParameters;
import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration;
import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.WebSocketConfiguration;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.metrics.prometheus.MetricsConfiguration;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.GenesisConfigProvider;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.factory.PantheonFactoryConfiguration;
import java.util.List;
import java.util.Optional;
public class PrivacyPantheonFactoryConfiguration extends PantheonFactoryConfiguration {
private final OrionTestHarness orion;
PrivacyPantheonFactoryConfiguration(
final String name,
final MiningParameters miningParameters,
final PrivacyParameters privacyParameters,
final JsonRpcConfiguration jsonRpcConfiguration,
final WebSocketConfiguration webSocketConfiguration,
final MetricsConfiguration metricsConfiguration,
final Optional<PermissioningConfiguration> permissioningConfiguration,
final Optional<String> keyFilePath,
final boolean devMode,
final GenesisConfigProvider genesisConfigProvider,
final boolean p2pEnabled,
final boolean discoveryEnabled,
final boolean bootnodeEligible,
final List<String> plugins,
final List<String> extraCLIOptions,
final OrionTestHarness orion) {
super(
name,
miningParameters,
privacyParameters,
jsonRpcConfiguration,
webSocketConfiguration,
metricsConfiguration,
permissioningConfiguration,
keyFilePath,
devMode,
genesisConfigProvider,
p2pEnabled,
discoveryEnabled,
bootnodeEligible,
plugins,
extraCLIOptions);
this.orion = orion;
}
public OrionTestHarness getOrion() {
return orion;
}
}

@ -0,0 +1,53 @@
/*
* Copyright 2018 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.privacy;
import tech.pegasys.orion.testutil.OrionTestHarness;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.factory.PantheonFactoryConfiguration;
public class PrivacyPantheonFactoryConfigurationBuilder {
protected PantheonFactoryConfiguration config;
protected OrionTestHarness orion;
public PrivacyPantheonFactoryConfigurationBuilder setConfig(
final PantheonFactoryConfiguration config) {
this.config = config;
return this;
}
public PrivacyPantheonFactoryConfigurationBuilder setOrion(final OrionTestHarness orion) {
this.orion = orion;
return this;
}
public PrivacyPantheonFactoryConfiguration build() {
return new PrivacyPantheonFactoryConfiguration(
config.getName(),
config.getMiningParameters(),
config.getPrivacyParameters(),
config.getJsonRpcConfiguration(),
config.getWebSocketConfiguration(),
config.getMetricsConfiguration(),
config.getPermissioningConfiguration(),
config.getKeyFilePath(),
config.isDevMode(),
config.getGenesisConfigProvider(),
config.isP2pEnabled(),
config.isDiscoveryEnabled(),
config.isBootnodeEligible(),
config.getPlugins(),
config.getExtraCLIOptions(),
orion);
}
}

@ -0,0 +1,108 @@
/*
* 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.privacy;
import tech.pegasys.orion.testutil.OrionTestHarness;
import tech.pegasys.pantheon.ethereum.core.PrivacyParameters;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.factory.PantheonFactoryConfigurationBuilder;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.factory.PantheonNodeFactoryUtils;
import java.io.IOException;
public class PrivacyPantheonNodeFactory extends PantheonNodeFactoryUtils {
private static PrivacyNode create(final PrivacyPantheonFactoryConfiguration config)
throws IOException {
return new PrivacyNode(
config.getName(),
config.getMiningParameters(),
config.getPrivacyParameters(),
config.getJsonRpcConfiguration(),
config.getWebSocketConfiguration(),
config.getMetricsConfiguration(),
config.getPermissioningConfiguration(),
config.getKeyFilePath(),
config.isDevMode(),
config.getGenesisConfigProvider(),
config.isP2pEnabled(),
config.isDiscoveryEnabled(),
config.isBootnodeEligible(),
config.getPlugins(),
config.getExtraCLIOptions(),
config.getOrion());
}
public PrivacyNode createPrivateTransactionEnabledMinerNode(
final String name,
final PrivacyParameters privacyParameters,
final String keyFilePath,
final OrionTestHarness orionTestHarness)
throws IOException {
return create(
new PrivacyPantheonFactoryConfigurationBuilder()
.setConfig(
new PantheonFactoryConfigurationBuilder()
.name(name)
.miningEnabled()
.jsonRpcEnabled()
.keyFilePath(keyFilePath)
.enablePrivateTransactions(privacyParameters)
.webSocketEnabled()
.build())
.setOrion(orionTestHarness)
.build());
}
public PrivacyNode createPrivateTransactionEnabledNode(
final String name,
final PrivacyParameters privacyParameters,
final String keyFilePath,
final OrionTestHarness orionTestHarness)
throws IOException {
return create(
new PrivacyPantheonFactoryConfigurationBuilder()
.setConfig(
new PantheonFactoryConfigurationBuilder()
.name(name)
.jsonRpcEnabled()
.keyFilePath(keyFilePath)
.enablePrivateTransactions(privacyParameters)
.webSocketEnabled()
.build())
.setOrion(orionTestHarness)
.build());
}
public PrivacyNode createIbftNodePrivacyEnabled(
final String name,
final PrivacyParameters privacyParameters,
final String keyFilePath,
final OrionTestHarness orionTestHarness)
throws IOException {
return create(
new PrivacyPantheonFactoryConfigurationBuilder()
.setConfig(
new PantheonFactoryConfigurationBuilder()
.name(name)
.miningEnabled()
.jsonRpcConfiguration(createJsonRpcConfigWithIbft())
.webSocketConfiguration(createWebSocketEnabledConfig())
.devMode(false)
.genesisConfigProvider(this::createIbftGenesisConfig)
.keyFilePath(keyFilePath)
.enablePrivateTransactions(privacyParameters)
.build())
.setOrion(orionTestHarness)
.build());
}
}

@ -12,6 +12,13 @@
*/
package tech.pegasys.pantheon.tests.acceptance.dsl.privacy;
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.eea.ExpectNoPrivateContractDeployedReceipt;
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.eea.ExpectNoValidPrivateContractEventsEmitted;
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.eea.ExpectNoValidPrivateContractValuesReturned;
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.eea.ExpectValidPrivateContractDeployedReceipt;
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.eea.ExpectValidPrivateContractEventsEmitted;
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.eea.ExpectValidPrivateContractValuesReturned;
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.eea.ExpectValidPrivateTransactionReceipt;
import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Eea;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transactions;
@ -42,6 +49,10 @@ public class PrivateTransactionVerifier {
return new ExpectValidPrivateContractEventsEmitted(eventValue, eea, transactions);
}
public ExpectNoValidPrivateContractEventsEmitted noValidEventReturned() {
return new ExpectNoValidPrivateContractEventsEmitted(eea, transactions);
}
public ExpectValidPrivateContractValuesReturned validOutputReturned(final String returnValue) {
return new ExpectValidPrivateContractValuesReturned(returnValue, eea, transactions);
}

@ -12,127 +12,54 @@
*/
package tech.pegasys.pantheon.tests.web3j.privacy;
import static java.nio.charset.StandardCharsets.UTF_8;
import static tech.pegasys.pantheon.tests.acceptance.dsl.WaitUtils.waitFor;
import tech.pegasys.pantheon.tests.acceptance.dsl.privacy.PrivacyAcceptanceTestBase;
import tech.pegasys.pantheon.tests.acceptance.dsl.privacy.PrivacyNet;
import tech.pegasys.orion.testutil.OrionTestHarness;
import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode;
import tech.pegasys.pantheon.tests.acceptance.dsl.privacy.PrivateAcceptanceTestBase;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eea.PrivateTransactionBuilder.TransactionType;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import java.math.BigInteger;
import com.google.common.collect.Lists;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class DeployPrivateSmartContractAcceptanceTest extends PrivateAcceptanceTestBase {
public class DeployPrivateSmartContractAcceptanceTest extends PrivacyAcceptanceTestBase {
// Contract address is generated from sender address and transaction nonce and privacy group id
protected static final Address CONTRACT_ADDRESS =
Address.fromHexString("0x06088ead8384df709132151403e08c2b978beb85");
protected static final String PUBLIC_KEY = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=";
private SECP256K1.KeyPair keypair =
SECP256K1.KeyPair.create(
SECP256K1.PrivateKey.create(
new BigInteger(
"8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", 16)));
protected static final String CONTRACT_NAME = "Event Emitter";
private PantheonNode minerNode;
private static OrionTestHarness enclave;
private String deployContract;
private String storeValue;
private String getValue;
private EventEmitterHarness eventEmitterHarness;
private PrivacyNet privacyNet;
@Before
public void setUp() throws Exception {
enclave = createEnclave("orion_key_0.pub", "orion_key_0.key");
minerNode =
pantheon.createPrivateTransactionEnabledMinerNode(
"miner-node", getPrivacyParameters(enclave), "key");
cluster.start(minerNode);
deployContract =
privateTransactionBuilder
.nonce(0)
.from(minerNode.getAddress())
.to(null)
.privateFrom(BytesValue.wrap(PUBLIC_KEY.getBytes(UTF_8)))
.privateFor(Lists.newArrayList())
.keyPair(keypair)
.build(TransactionType.CREATE_CONTRACT);
storeValue =
privateTransactionBuilder
.nonce(1)
.from(minerNode.getAddress())
.to(CONTRACT_ADDRESS)
.privateFrom(BytesValue.wrap(PUBLIC_KEY.getBytes(UTF_8)))
.privateFor(Lists.newArrayList())
.keyPair(keypair)
.build(TransactionType.STORE);
getValue =
privateTransactionBuilder
.nonce(2)
.from(minerNode.getAddress())
.to(CONTRACT_ADDRESS)
.privateFrom(BytesValue.wrap(PUBLIC_KEY.getBytes(UTF_8)))
.privateFor(Lists.newArrayList())
.keyPair(keypair)
.build(TransactionType.GET);
privacyNet =
PrivacyNet.builder(privacy, privacyPantheon, cluster, false).addMinerNode("Alice").build();
privacyNet.startPrivacyNet();
eventEmitterHarness =
new EventEmitterHarness(
privateTransactionBuilder,
privacyNet,
privateTransactions,
privateTransactionVerifier,
eea);
}
@Test
public void deployingMustGiveValidReceipt() {
final String transactionHash =
minerNode.execute(privateTransactions.deployPrivateSmartContract(deployContract));
privateTransactionVerifier
.validPrivateContractDeployed(CONTRACT_ADDRESS.toString())
.verify(minerNode, transactionHash);
eventEmitterHarness.deploy(CONTRACT_NAME, "Alice");
}
@Test
public void privateSmartContractMustEmitEvents() {
String transactionHash =
minerNode.execute(privateTransactions.deployPrivateSmartContract(deployContract));
waitForTransactionToBeMined(transactionHash);
transactionHash =
minerNode.execute(privateTransactions.createPrivateRawTransaction(storeValue));
privateTransactionVerifier.validEventReturned("1000").verify(minerNode, transactionHash);
eventEmitterHarness.deploy(CONTRACT_NAME, "Alice");
eventEmitterHarness.store(CONTRACT_NAME, "Alice");
}
@Test
public void privateSmartContractMustReturnValues() {
String transactionHash =
minerNode.execute(privateTransactions.deployPrivateSmartContract(deployContract));
waitForTransactionToBeMined(transactionHash);
transactionHash =
minerNode.execute(privateTransactions.createPrivateRawTransaction(storeValue));
waitForTransactionToBeMined(transactionHash);
transactionHash = minerNode.execute(privateTransactions.createPrivateRawTransaction(getValue));
privateTransactionVerifier.validOutputReturned("1000").verify(minerNode, transactionHash);
eventEmitterHarness.deploy(CONTRACT_NAME, "Alice");
eventEmitterHarness.store(CONTRACT_NAME, "Alice");
eventEmitterHarness.get(CONTRACT_NAME, "Alice");
}
@After
public void tearDown() {
enclave.getOrion().stop();
}
public void waitForTransactionToBeMined(final String transactionHash) {
waitFor(() -> minerNode.verify(eea.expectSuccessfulTransactionReceipt(transactionHash)));
privacyNet.stopPrivacyNet();
}
}

@ -0,0 +1,297 @@
/*
* 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 java.nio.charset.StandardCharsets.UTF_8;
import static tech.pegasys.pantheon.tests.acceptance.dsl.WaitUtils.waitFor;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.eea.EeaCondition;
import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Eea;
import tech.pegasys.pantheon.tests.acceptance.dsl.privacy.PrivacyNet;
import tech.pegasys.pantheon.tests.acceptance.dsl.privacy.PrivateTransactionVerifier;
import tech.pegasys.pantheon.tests.acceptance.dsl.privacy.PrivateTransactions;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eea.PrivateTransactionBuilder;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.web3j.crypto.Hash;
import org.web3j.rlp.RlpEncoder;
import org.web3j.rlp.RlpList;
import org.web3j.rlp.RlpString;
import org.web3j.rlp.RlpType;
import org.web3j.utils.Numeric;
public class EventEmitterHarness {
private PrivateTransactionBuilder.Builder privateTransactionBuilder;
private PrivacyNet privacyNet;
private PrivateTransactions privateTransactions;
private PrivateTransactionVerifier privateTransactionVerifier;
private Eea eea;
private Map<String, String> contracts;
public EventEmitterHarness(
final PrivateTransactionBuilder.Builder privateTransactionBuilder,
final PrivacyNet privacyNet,
final PrivateTransactions privateTransactions,
final PrivateTransactionVerifier privateTransactionVerifier,
final Eea eea) {
this.privateTransactionBuilder = privateTransactionBuilder;
this.privacyNet = privacyNet;
this.privateTransactions = privateTransactions;
this.privateTransactionVerifier = privateTransactionVerifier;
this.eea = eea;
this.contracts = new HashMap<>();
}
public String resolveContractAddress(final String contractName) {
return contracts.get(contractName);
}
public void deploy(final String contractName, final String sender, final String... receivers) {
final BytesValue privacyGroupId = generatePrivaycGroup(sender, receivers);
final long nonce = nextNonce(sender, privacyGroupId);
final String contractAddress =
generateContractAddress(sender, nonce, privacyGroupId).toString();
deploy(
contractName,
privateTransactionVerifier.validPrivateContractDeployed(contractAddress),
privateTransactionVerifier.noPrivateContractDeployed(),
sender,
receivers);
}
public void deploy(
final String contractName,
final EeaCondition forParticipants,
final EeaCondition forNonParticipants,
final String sender,
final String... receivers) {
final BytesValue privacyGroupId = generatePrivaycGroup(sender, receivers);
final long nonce = nextNonce(sender, privacyGroupId);
final String contractAddress =
generateContractAddress(sender, nonce, privacyGroupId).toString();
deploy(
contractAddress,
contractName,
nonce,
forParticipants,
forNonParticipants,
sender,
receivers);
}
public void store(final String contractName, final String sender, final String... receivers) {
store(
contractName,
privateTransactionVerifier.validEventReturned("1000"),
privateTransactionVerifier.noValidEventReturned(),
sender,
receivers);
}
public void store(
final String contractName,
final EeaCondition forParticipants,
final EeaCondition forNonParticipants,
final String sender,
final String... receivers) {
final String contractAddress = resolveContractAddress(contractName);
final BytesValue privacyGroupId = generatePrivaycGroup(sender, receivers);
final long nonce = nextNonce(sender, privacyGroupId);
final String storeValue =
privateTransactionBuilder
.nonce(nonce)
.from(privacyNet.getPantheon(sender).getAddress())
.to(Address.fromHexString(contractAddress))
.privateFrom(
BytesValue.wrap(
privacyNet.getEnclave(sender).getPublicKeys().get(0).getBytes(UTF_8)))
.privateFor(convertNamesToOrionPublicKeys(receivers))
.keyPair(privacyNet.getPantheon(sender).keyPair())
.build(PrivateTransactionBuilder.TransactionType.STORE);
final String transactionHash =
privacyNet
.getPantheon(sender)
.execute(privateTransactions.createPrivateRawTransaction(storeValue));
waitForTransactionToBeMined(transactionHash);
verifyForParticipants(forParticipants, transactionHash, sender, receivers);
verifyForNonParticipants(forNonParticipants, transactionHash, sender, receivers);
}
public void get(final String contractName, final String sender, final String... receivers) {
get(
contractName,
privateTransactionVerifier.validOutputReturned("1000"),
privateTransactionVerifier.noValidOutputReturned(),
sender,
receivers);
}
public void get(
final String contractName,
final EeaCondition forParticipants,
final EeaCondition forNonParticipants,
final String sender,
final String... receivers) {
final String contractAddress = resolveContractAddress(contractName);
final BytesValue privacyGroupId = generatePrivaycGroup(sender, receivers);
final long nonce = nextNonce(sender, privacyGroupId);
final String getValue =
privateTransactionBuilder
.nonce(nonce)
.from(privacyNet.getPantheon(sender).getAddress())
.to(Address.fromHexString(contractAddress))
.privateFrom(
BytesValue.wrap(
privacyNet.getEnclave(sender).getPublicKeys().get(0).getBytes(UTF_8)))
.privateFor(convertNamesToOrionPublicKeys(receivers))
.keyPair(privacyNet.getPantheon(sender).keyPair())
.build(PrivateTransactionBuilder.TransactionType.GET);
final String transactionHash =
privacyNet
.getPantheon(sender)
.execute(privateTransactions.createPrivateRawTransaction(getValue));
waitForTransactionToBeMined(transactionHash);
verifyForParticipants(forParticipants, transactionHash, sender, receivers);
verifyForNonParticipants(forNonParticipants, transactionHash, sender, receivers);
}
private void deploy(
final String contractAddress,
final String contractName,
final long nonce,
final EeaCondition forParticipants,
final EeaCondition forNonParticipants,
final String sender,
final String... receivers) {
final String deployContract =
privateTransactionBuilder
.nonce(nonce)
.from(privacyNet.getPantheon(sender).getAddress())
.to(null)
.privateFrom(
BytesValue.wrap(
privacyNet.getEnclave(sender).getPublicKeys().get(0).getBytes(UTF_8)))
.privateFor(convertNamesToOrionPublicKeys(receivers))
.keyPair(privacyNet.getPantheon(sender).keyPair())
.build(PrivateTransactionBuilder.TransactionType.CREATE_CONTRACT);
final String transactionHash =
privacyNet
.getPantheon(sender)
.execute(privateTransactions.deployPrivateSmartContract(deployContract));
waitForTransactionToBeMined(transactionHash);
verifyForParticipants(forParticipants, transactionHash, sender, receivers);
verifyForNonParticipants(forNonParticipants, transactionHash, sender, receivers);
contracts.put(contractName, contractAddress);
}
private Address generateContractAddress(
final String sender, final long nonce, final BytesValue privacyGroupId) {
return Address.privateContractAddress(
privacyNet.getPantheon(sender).getAddress(), nonce, privacyGroupId);
}
private BytesValue generatePrivaycGroup(final String sender, final String[] receivers) {
final List<byte[]> stringList = new ArrayList<>();
stringList.add(
Base64.getDecoder().decode(privacyNet.getEnclave(sender).getPublicKeys().get(0)));
Arrays.stream(receivers)
.forEach(
(receiver) ->
stringList.add(
Base64.getDecoder()
.decode(privacyNet.getEnclave(receiver).getPublicKeys().get(0))));
List<RlpType> rlpList =
stringList.stream()
.distinct()
.sorted(Comparator.comparing(Arrays::hashCode))
.map(RlpString::create)
.collect(Collectors.toList());
return BytesValue.fromHexString(
Numeric.toHexString(
Base64.getEncoder().encode(Hash.sha3(RlpEncoder.encode(new RlpList(rlpList))))));
}
private long nextNonce(final String sender, final BytesValue privacyGroupId) {
return privacyNet
.getPantheon(sender)
.execute(
privateTransactions.getTransactionCount(
privacyNet.getPantheon(sender).getAddress().toString(), privacyGroupId.toString()))
.longValue();
}
private void waitForTransactionToBeMined(final String transactionHash) {
waitFor(
() ->
privacyNet
.getPantheon("Alice")
.verify(eea.expectSuccessfulTransactionReceipt(transactionHash)));
}
private List<BytesValue> convertNamesToOrionPublicKeys(final String... toNodeNames) {
return Arrays.stream(toNodeNames)
.map(
name ->
BytesValue.wrap(privacyNet.getEnclave(name).getPublicKeys().get(0).getBytes(UTF_8)))
.collect(Collectors.toList());
}
private void verifyForNonParticipants(
final EeaCondition condition,
final String transactionHash,
final String sender,
final String[] receivers) {
privacyNet.getNodes().keySet().stream()
.filter(key -> !sender.equals(key) && !Arrays.asList(receivers).contains(key))
.forEach(node -> verifyForParticipant(condition, transactionHash, node));
}
private void verifyForParticipants(
final EeaCondition condition,
final String transactionHash,
final String fromNodeName,
final String[] toNodeNames) {
verifyForParticipant(condition, transactionHash, fromNodeName);
Arrays.stream(toNodeNames)
.forEach(node -> verifyForParticipant(condition, transactionHash, fromNodeName));
}
private void verifyForParticipant(
final EeaCondition condition, final String transactionHash, final String nodeName) {
condition.verify(privacyNet.getPantheon(nodeName), transactionHash);
}
}

@ -0,0 +1,134 @@
/*
* 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 java.nio.charset.StandardCharsets.UTF_8;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.tests.acceptance.dsl.privacy.PrivacyAcceptanceTestBase;
import tech.pegasys.pantheon.tests.acceptance.dsl.privacy.PrivacyNet;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eea.PrivateTransactionBuilder;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eea.PrivateTransactionBuilder.TransactionType;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import com.google.common.collect.Lists;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class IbftPrivacyClusterAcceptanceTest extends PrivacyAcceptanceTestBase {
private static final String CONTRACT_NAME = "Event Emmiter";
private EventEmitterHarness eventEmitterHarness;
private PrivacyNet privacyNet;
@Before
public void setUp() throws Exception {
privacyNet =
PrivacyNet.builder(privacy, privacyPantheon, cluster, false)
.addMinerNode("Alice")
.addMinerNode("Bob")
.addMinerNode("Charlie")
.build();
privacyNet.startPrivacyNet();
eventEmitterHarness =
new EventEmitterHarness(
privateTransactionBuilder,
privacyNet,
privateTransactions,
privateTransactionVerifier,
eea);
}
@Test
public void node2CanSeeContract() {
eventEmitterHarness.deploy(CONTRACT_NAME, "Alice", "Bob");
}
@Test
public void node2CanExecuteContract() {
eventEmitterHarness.deploy(CONTRACT_NAME, "Alice", "Bob");
eventEmitterHarness.store(CONTRACT_NAME, "Bob", "Alice");
}
@Test
public void node2CanSeePrivateTransactionReceipt() {
eventEmitterHarness.deploy(CONTRACT_NAME, "Alice", "Bob");
eventEmitterHarness.store(CONTRACT_NAME, "Bob", "Alice");
eventEmitterHarness.get(CONTRACT_NAME, "Bob", "Alice");
}
@Test(expected = RuntimeException.class)
public void node2ExpectError() {
eventEmitterHarness.deploy(CONTRACT_NAME, "Alice", "Bob");
String invalidStoreValueFromNode2 =
PrivateTransactionBuilder.builder()
.nonce(0)
.from(privacyNet.getPantheon("Bob").getAddress())
.to(Address.fromHexString(eventEmitterHarness.resolveContractAddress(CONTRACT_NAME)))
.privateFrom(
BytesValue.wrap(
privacyNet
.getEnclave("Alice")
.getPublicKeys()
.get(0)
.getBytes(UTF_8))) // wrong public key
.privateFor(
Lists.newArrayList(
BytesValue.wrap(
privacyNet.getEnclave("Bob").getPublicKeys().get(0).getBytes(UTF_8))))
.keyPair(privacyNet.getPantheon("Bob").keyPair())
.build(TransactionType.STORE);
privacyNet
.getPantheon("Bob")
.execute(privateTransactions.createPrivateRawTransaction(invalidStoreValueFromNode2));
}
@Test
public void node1CanDeployMultipleTimes() {
eventEmitterHarness.deploy(CONTRACT_NAME, "Alice", "Bob");
eventEmitterHarness.store(CONTRACT_NAME, "Bob", "Alice");
final String secondContract = "Event Emitter 2";
eventEmitterHarness.deploy(secondContract, "Alice", "Bob");
eventEmitterHarness.store(secondContract, "Bob", "Alice");
}
@Test
public void node1CanInteractWithMultiplePrivacyGroups() {
eventEmitterHarness.deploy(CONTRACT_NAME, "Alice", "Bob", "Charlie");
eventEmitterHarness.store(CONTRACT_NAME, "Alice", "Bob", "Charlie");
final String secondContract = "Event Emitter 2";
eventEmitterHarness.store(
secondContract,
privateTransactionVerifier.noValidEventReturned(),
privateTransactionVerifier.noValidEventReturned(),
"Alice",
"Bob");
eventEmitterHarness.deploy(secondContract, "Alice", "Bob");
eventEmitterHarness.store(secondContract, "Alice", "Bob");
eventEmitterHarness.get(secondContract, "Alice", "Bob");
}
@After
public void tearDown() {
privacyNet.stopPrivacyNet();
}
}

@ -13,505 +13,122 @@
package tech.pegasys.pantheon.tests.web3j.privacy;
import static java.nio.charset.StandardCharsets.UTF_8;
import static tech.pegasys.pantheon.tests.acceptance.dsl.WaitUtils.waitFor;
import tech.pegasys.orion.testutil.OrionTestHarness;
import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.enclave.Enclave;
import tech.pegasys.pantheon.enclave.types.SendRequest;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode;
import tech.pegasys.pantheon.tests.acceptance.dsl.privacy.PrivateAcceptanceTestBase;
import tech.pegasys.pantheon.tests.acceptance.dsl.privacy.PrivacyAcceptanceTestBase;
import tech.pegasys.pantheon.tests.acceptance.dsl.privacy.PrivacyNet;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eea.PrivateTransactionBuilder;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eea.PrivateTransactionBuilder.TransactionType;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import java.math.BigInteger;
import com.google.common.collect.Lists;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class PrivacyClusterAcceptanceTest extends PrivateAcceptanceTestBase {
// Contract address is generated from sender address and transaction nonce and privacy group id
private static final Address CONTRACT_ADDRESS =
Address.fromHexString("0x2f351161a80d74047316899342eedc606b13f9f8");
private static final String PUBLIC_KEY_1 = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=";
private static final String PUBLIC_KEY_2 = "Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs=";
private static final String PUBLIC_KEY_3 = "k2zXEin4Ip/qBGlRkJejnGWdP9cjkK+DAvKNW31L2C8=";
private SECP256K1.KeyPair keypair1 =
SECP256K1.KeyPair.create(
SECP256K1.PrivateKey.create(
new BigInteger(
"8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", 16)));
private SECP256K1.KeyPair keypair2 =
SECP256K1.KeyPair.create(
SECP256K1.PrivateKey.create(
new BigInteger(
"c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3", 16)));
private SECP256K1.KeyPair keypair3 =
SECP256K1.KeyPair.create(
SECP256K1.PrivateKey.create(
new BigInteger(
"ae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f", 16)));
private PantheonNode node1;
private PantheonNode node2;
private PantheonNode node3;
private static OrionTestHarness enclave1;
private static OrionTestHarness enclave2;
private static OrionTestHarness enclave3;
public class PrivacyClusterAcceptanceTest extends PrivacyAcceptanceTestBase {
private static final String CONTRACT_NAME = "Event Emmiter";
private String deployContractFromNode1;
private String storeValueFromNode2;
private String getValueFromNode2;
private String getValueFromNode3;
private EventEmitterHarness eventEmitterHarness;
private PrivacyNet privacyNet;
@Before
public void setUp() throws Exception {
enclave1 = createEnclave("orion_key_0.pub", "orion_key_0.key");
enclave2 = createEnclave("orion_key_1.pub", "orion_key_1.key", enclave1.nodeUrl());
enclave3 = createEnclave("orion_key_2.pub", "orion_key_2.key", enclave2.nodeUrl());
node1 =
pantheon.createPrivateTransactionEnabledMinerNode(
"node1", getPrivacyParameters(enclave1), "key");
node2 =
pantheon.createPrivateTransactionEnabledMinerNode(
"node2", getPrivacyParameters(enclave2), "key1");
node3 =
pantheon.createPrivateTransactionEnabledNode(
"node3", getPrivacyParameters(enclave3), "key2");
cluster.start(node1, node2, node3);
// Wait for enclave 1 and enclave 2 to connect
Enclave orion1 = new Enclave(enclave1.clientUrl());
SendRequest sendRequest1 =
new SendRequest(
"SGVsbG8sIFdvcmxkIQ==", enclave1.getPublicKeys().get(0), enclave2.getPublicKeys());
waitFor(() -> orion1.send(sendRequest1));
// Wait for enclave 2 and enclave 3 to connect
Enclave orion2 = new Enclave(enclave2.clientUrl());
SendRequest sendRequest2 =
new SendRequest(
"SGVsbG8sIFdvcmxkIQ==", enclave2.getPublicKeys().get(0), enclave3.getPublicKeys());
waitFor(() -> orion2.send(sendRequest2));
// Wait for enclave 1 and enclave 3 to connect
Enclave orion3 = new Enclave(enclave3.clientUrl());
SendRequest sendRequest3 =
new SendRequest(
"SGVsbG8sIFdvcmxkIQ==", enclave3.getPublicKeys().get(0), enclave1.getPublicKeys());
waitFor(() -> orion3.send(sendRequest3));
deployContractFromNode1 =
PrivateTransactionBuilder.builder()
.nonce(0)
.from(node1.getAddress())
.to(null)
.privateFrom(BytesValue.wrap(PUBLIC_KEY_1.getBytes(UTF_8)))
.privateFor(Lists.newArrayList(BytesValue.wrap(PUBLIC_KEY_2.getBytes(UTF_8))))
.keyPair(keypair1)
.build(TransactionType.CREATE_CONTRACT);
storeValueFromNode2 =
PrivateTransactionBuilder.builder()
.nonce(0)
.from(node2.getAddress())
.to(CONTRACT_ADDRESS)
.privateFrom(BytesValue.wrap(PUBLIC_KEY_2.getBytes(UTF_8)))
.privateFor(Lists.newArrayList(BytesValue.wrap(PUBLIC_KEY_1.getBytes(UTF_8))))
.keyPair(keypair2)
.build(TransactionType.STORE);
getValueFromNode2 =
PrivateTransactionBuilder.builder()
.nonce(1)
.from(node2.getAddress())
.to(CONTRACT_ADDRESS)
.privateFrom(BytesValue.wrap(PUBLIC_KEY_2.getBytes(UTF_8)))
.privateFor(Lists.newArrayList(BytesValue.wrap(PUBLIC_KEY_1.getBytes(UTF_8))))
.keyPair(keypair2)
.build(TransactionType.GET);
getValueFromNode3 =
PrivateTransactionBuilder.builder()
.nonce(0)
.from(node3.getAddress())
.to(CONTRACT_ADDRESS)
.privateFrom(BytesValue.wrap(PUBLIC_KEY_3.getBytes(UTF_8)))
.privateFor(Lists.newArrayList(BytesValue.wrap(PUBLIC_KEY_2.getBytes(UTF_8))))
.keyPair(keypair3)
.build(TransactionType.GET);
privacyNet =
PrivacyNet.builder(privacy, privacyPantheon, cluster, false)
.addMinerNode("Alice")
.addMinerNode("Bob")
.addMinerNode("Charlie")
.build();
privacyNet.startPrivacyNet();
eventEmitterHarness =
new EventEmitterHarness(
privateTransactionBuilder,
privacyNet,
privateTransactions,
privateTransactionVerifier,
eea);
}
@Test
public void node2CanSeeContract() {
String transactionHash =
node1.execute(privateTransactions.deployPrivateSmartContract(deployContractFromNode1));
privateTransactionVerifier
.validPrivateContractDeployed(CONTRACT_ADDRESS.toString())
.verify(node2, transactionHash);
eventEmitterHarness.deploy(CONTRACT_NAME, "Alice", "Bob");
}
@Test
public void node2CanExecuteContract() {
String transactionHash =
node1.execute(privateTransactions.deployPrivateSmartContract(deployContractFromNode1));
privateTransactionVerifier
.validPrivateContractDeployed(CONTRACT_ADDRESS.toString())
.verify(node2, transactionHash);
transactionHash =
node2.execute(privateTransactions.createPrivateRawTransaction(storeValueFromNode2));
privateTransactionVerifier.validEventReturned("1000").verify(node1, transactionHash);
eventEmitterHarness.deploy(CONTRACT_NAME, "Alice", "Bob");
eventEmitterHarness.store(CONTRACT_NAME, "Bob", "Alice");
}
@Test
public void node2CanSeePrivateTransactionReceipt() {
String transactionHash =
node1.execute(privateTransactions.deployPrivateSmartContract(deployContractFromNode1));
privateTransactionVerifier
.validPrivateContractDeployed(CONTRACT_ADDRESS.toString())
.verify(node2, transactionHash);
transactionHash =
node2.execute(privateTransactions.createPrivateRawTransaction(storeValueFromNode2));
privateTransactionVerifier.validEventReturned("1000").verify(node1, transactionHash);
transactionHash =
node2.execute(privateTransactions.createPrivateRawTransaction(getValueFromNode2));
privateTransactionVerifier.validOutputReturned("1000").verify(node2, transactionHash);
privateTransactionVerifier.validOutputReturned("1000").verify(node1, transactionHash);
}
@Test
public void node3CannotSeeContract() {
final String transactionHash =
node1.execute(privateTransactions.deployPrivateSmartContract(deployContractFromNode1));
privateTransactionVerifier.noPrivateContractDeployed().verify(node3, transactionHash);
}
@Test
public void node3CannotExecuteContract() {
node1.execute(privateTransactions.deployPrivateSmartContract(deployContractFromNode1));
final String transactionHash =
node3.execute(privateTransactions.createPrivateRawTransaction(getValueFromNode3));
privateTransactionVerifier.noValidOutputReturned().verify(node3, transactionHash);
eventEmitterHarness.deploy(CONTRACT_NAME, "Alice", "Bob");
eventEmitterHarness.store(CONTRACT_NAME, "Bob", "Alice");
eventEmitterHarness.get(CONTRACT_NAME, "Bob", "Alice");
}
@Test(expected = RuntimeException.class)
public void node2ExpectError() {
node1.execute(privateTransactions.deployPrivateSmartContract(deployContractFromNode1));
eventEmitterHarness.deploy(CONTRACT_NAME, "Alice", "Bob");
String invalidStoreValueFromNode2 =
PrivateTransactionBuilder.builder()
.nonce(0)
.from(node2.getAddress())
.to(CONTRACT_ADDRESS)
.privateFrom(BytesValue.wrap(PUBLIC_KEY_1.getBytes(UTF_8))) // wrong public key
.privateFor(Lists.newArrayList(BytesValue.wrap(PUBLIC_KEY_2.getBytes(UTF_8))))
.keyPair(keypair2)
.from(privacyNet.getPantheon("Bob").getAddress())
.to(Address.fromHexString(eventEmitterHarness.resolveContractAddress(CONTRACT_NAME)))
.privateFrom(
BytesValue.wrap(
privacyNet
.getEnclave("Alice")
.getPublicKeys()
.get(0)
.getBytes(UTF_8))) // wrong public key
.privateFor(
Lists.newArrayList(
BytesValue.wrap(
privacyNet.getEnclave("Bob").getPublicKeys().get(0).getBytes(UTF_8))))
.keyPair(privacyNet.getPantheon("Bob").keyPair())
.build(TransactionType.STORE);
node2.execute(privateTransactions.createPrivateRawTransaction(invalidStoreValueFromNode2));
privacyNet
.getPantheon("Bob")
.execute(privateTransactions.createPrivateRawTransaction(invalidStoreValueFromNode2));
}
@Test
public void node1CanDeployMultipleTimes() {
final String privacyGroup12 =
"0x4479414f69462f796e70632b4a586132594147423062436974536c4f4d4e6d2b53686d422f374d364334773d";
long nextNonce = getNonce(node1, privacyGroup12);
final Address contractFor12 =
generateContractAddress(node1.getAddress(), nextNonce, privacyGroup12);
final String deployContractFor12 =
PrivateTransactionBuilder.builder()
.nonce(nextNonce)
.from(node1.getAddress())
.to(null)
.privateFrom(BytesValue.wrap(PUBLIC_KEY_1.getBytes(UTF_8)))
.privateFor(Lists.newArrayList(BytesValue.wrap(PUBLIC_KEY_2.getBytes(UTF_8))))
.keyPair(keypair1)
.build(TransactionType.CREATE_CONTRACT);
String transactionHash =
node1.execute(privateTransactions.deployPrivateSmartContract(deployContractFor12));
privateTransactionVerifier
.validPrivateContractDeployed(contractFor12.toString())
.verify(node1, transactionHash);
nextNonce = getNonce(node2, privacyGroup12);
final String storeValueFor12 =
PrivateTransactionBuilder.builder()
.nonce(nextNonce)
.from(node2.getAddress())
.to(contractFor12)
.privateFrom(BytesValue.wrap(PUBLIC_KEY_2.getBytes(UTF_8)))
.privateFor(Lists.newArrayList(BytesValue.wrap(PUBLIC_KEY_1.getBytes(UTF_8))))
.keyPair(keypair2)
.build(TransactionType.STORE);
transactionHash =
node2.execute(privateTransactions.createPrivateRawTransaction(storeValueFor12));
privateTransactionVerifier.validEventReturned("1000").verify(node1, transactionHash);
eventEmitterHarness.deploy(CONTRACT_NAME, "Alice", "Bob");
eventEmitterHarness.store(CONTRACT_NAME, "Bob", "Alice");
nextNonce = getNonce(node1, privacyGroup12);
final String secondContract = "Event Emitter 2";
final Address contractFor12Again =
Address.privateContractAddress(
node1.getAddress(), nextNonce, BytesValue.fromHexString(privacyGroup12));
final String deployContractFor12Again =
PrivateTransactionBuilder.builder()
.nonce(nextNonce)
.from(node1.getAddress())
.to(null)
.privateFrom(BytesValue.wrap(PUBLIC_KEY_1.getBytes(UTF_8)))
.privateFor(Lists.newArrayList(BytesValue.wrap(PUBLIC_KEY_2.getBytes(UTF_8))))
.keyPair(keypair1)
.build(TransactionType.CREATE_CONTRACT);
transactionHash =
node1.execute(privateTransactions.deployPrivateSmartContract(deployContractFor12Again));
privateTransactionVerifier
.validPrivateContractDeployed(contractFor12Again.toString())
.verify(node1, transactionHash);
nextNonce = getNonce(node1, privacyGroup12);
final String storeValueFor12Again =
PrivateTransactionBuilder.builder()
.nonce(nextNonce)
.from(node1.getAddress())
.to(contractFor12)
.privateFrom(BytesValue.wrap(PUBLIC_KEY_1.getBytes(UTF_8)))
.privateFor(Lists.newArrayList(BytesValue.wrap(PUBLIC_KEY_2.getBytes(UTF_8))))
.keyPair(keypair1)
.build(TransactionType.STORE);
transactionHash =
node1.execute(privateTransactions.createPrivateRawTransaction(storeValueFor12Again));
privateTransactionVerifier.validEventReturned("1000").verify(node1, transactionHash);
eventEmitterHarness.deploy(secondContract, "Alice", "Bob");
eventEmitterHarness.store(secondContract, "Bob", "Alice");
}
@Test
public void node1CanInteractWithMultiplePrivacyGroups() {
final String privacyGroup123 =
"0x393579496e2f4f59545a31784e3753694258314d64424a763942716b364f713766792b37585361496e79593d";
final String privacyGroup12 =
"0x4479414f69462f796e70632b4a586132594147423062436974536c4f4d4e6d2b53686d422f374d364334773d";
long nextNonce = getNonce(node1, privacyGroup123);
final Address contractForABC =
generateContractAddress(node1.getAddress(), nextNonce, privacyGroup123);
final String deployContractFor123 =
PrivateTransactionBuilder.builder()
.nonce(nextNonce)
.from(node1.getAddress())
.to(null)
.privateFrom(BytesValue.wrap(PUBLIC_KEY_1.getBytes(UTF_8)))
.privateFor(
Lists.newArrayList(
BytesValue.wrap(PUBLIC_KEY_2.getBytes(UTF_8)),
BytesValue.wrap(PUBLIC_KEY_3.getBytes(UTF_8))))
.keyPair(keypair1)
.build(TransactionType.CREATE_CONTRACT);
String transactionHash =
node1.execute(privateTransactions.deployPrivateSmartContract(deployContractFor123));
privateTransactionVerifier
.validPrivateContractDeployed(contractForABC.toString())
.verify(node1, transactionHash);
nextNonce = getNonce(node1, privacyGroup123);
final String storeValueFor123 =
PrivateTransactionBuilder.builder()
.nonce(nextNonce)
.from(node1.getAddress())
.to(contractForABC)
.privateFrom(BytesValue.wrap(PUBLIC_KEY_1.getBytes(UTF_8)))
.privateFor(
Lists.newArrayList(
BytesValue.wrap(PUBLIC_KEY_2.getBytes(UTF_8)),
BytesValue.wrap(PUBLIC_KEY_3.getBytes(UTF_8))))
.keyPair(keypair1)
.build(TransactionType.STORE);
transactionHash =
node1.execute(privateTransactions.createPrivateRawTransaction(storeValueFor123));
privateTransactionVerifier.validEventReturned("1000").verify(node1, transactionHash);
nextNonce = getNonce(node1, privacyGroup12);
final String storeValueFor12BeforeDeployingContract =
PrivateTransactionBuilder.builder()
.nonce(nextNonce)
.from(node1.getAddress())
.to(contractForABC)
.privateFrom(BytesValue.wrap(PUBLIC_KEY_1.getBytes(UTF_8)))
.privateFor(Lists.newArrayList(BytesValue.wrap(PUBLIC_KEY_2.getBytes(UTF_8))))
.keyPair(keypair1)
.build(TransactionType.STORE);
transactionHash =
node1.execute(
privateTransactions.createPrivateRawTransaction(
storeValueFor12BeforeDeployingContract));
privateTransactionVerifier.noValidOutputReturned().verify(node1, transactionHash);
nextNonce = getNonce(node1, privacyGroup12);
final Address contractFor12 =
generateContractAddress(node1.getAddress(), nextNonce, privacyGroup12);
final String deployContractFor12 =
PrivateTransactionBuilder.builder()
.nonce(nextNonce)
.from(node1.getAddress())
.to(null)
.privateFrom(BytesValue.wrap(PUBLIC_KEY_1.getBytes(UTF_8)))
.privateFor(Lists.newArrayList(BytesValue.wrap(PUBLIC_KEY_2.getBytes(UTF_8))))
.keyPair(keypair1)
.build(TransactionType.CREATE_CONTRACT);
transactionHash =
node1.execute(privateTransactions.deployPrivateSmartContract(deployContractFor12));
privateTransactionVerifier
.validPrivateContractDeployed(contractFor12.toString())
.verify(node1, transactionHash);
eventEmitterHarness.deploy(CONTRACT_NAME, "Alice", "Bob", "Charlie");
eventEmitterHarness.store(CONTRACT_NAME, "Alice", "Bob", "Charlie");
nextNonce = getNonce(node1, privacyGroup12);
final String storeValueFor12 =
PrivateTransactionBuilder.builder()
.nonce(nextNonce)
.from(node1.getAddress())
.to(contractFor12)
.privateFrom(BytesValue.wrap(PUBLIC_KEY_1.getBytes(UTF_8)))
.privateFor(Lists.newArrayList(BytesValue.wrap(PUBLIC_KEY_2.getBytes(UTF_8))))
.keyPair(keypair1)
.build(TransactionType.STORE);
transactionHash =
node1.execute(privateTransactions.createPrivateRawTransaction(storeValueFor12));
privateTransactionVerifier.validEventReturned("1000").verify(node1, transactionHash);
}
@Test
public void node1AndNode2CanInteractInAPrivacyGroup() {
final String privacyGroup12 =
"0x4479414f69462f796e70632b4a586132594147423062436974536c4f4d4e6d2b53686d422f374d364334773d";
long nextNonce = getNonce(node1, privacyGroup12);
final Address contractFor12 =
generateContractAddress(node1.getAddress(), nextNonce, privacyGroup12);
final String deployContractFor12 =
PrivateTransactionBuilder.builder()
.nonce(nextNonce)
.from(node1.getAddress())
.to(null)
.privateFrom(BytesValue.wrap(PUBLIC_KEY_1.getBytes(UTF_8)))
.privateFor(Lists.newArrayList(BytesValue.wrap(PUBLIC_KEY_2.getBytes(UTF_8))))
.keyPair(keypair1)
.build(TransactionType.CREATE_CONTRACT);
String transactionHash =
node1.execute(privateTransactions.deployPrivateSmartContract(deployContractFor12));
privateTransactionVerifier
.validPrivateContractDeployed(contractFor12.toString())
.verify(node1, transactionHash);
nextNonce = getNonce(node2, privacyGroup12);
final String storeValueFor12 =
PrivateTransactionBuilder.builder()
.nonce(nextNonce)
.from(node2.getAddress())
.to(contractFor12)
.privateFrom(BytesValue.wrap(PUBLIC_KEY_2.getBytes(UTF_8)))
.privateFor(Lists.newArrayList(BytesValue.wrap(PUBLIC_KEY_1.getBytes(UTF_8))))
.keyPair(keypair2)
.build(TransactionType.STORE);
transactionHash =
node2.execute(privateTransactions.createPrivateRawTransaction(storeValueFor12));
privateTransactionVerifier.validEventReturned("1000").verify(node1, transactionHash);
nextNonce = getNonce(node1, privacyGroup12);
final Address contractFor12Again =
Address.privateContractAddress(
node1.getAddress(), nextNonce, BytesValue.fromHexString(privacyGroup12));
final String deployContractFor12Again =
PrivateTransactionBuilder.builder()
.nonce(nextNonce)
.from(node1.getAddress())
.to(null)
.privateFrom(BytesValue.wrap(PUBLIC_KEY_1.getBytes(UTF_8)))
.privateFor(Lists.newArrayList(BytesValue.wrap(PUBLIC_KEY_2.getBytes(UTF_8))))
.keyPair(keypair1)
.build(TransactionType.CREATE_CONTRACT);
transactionHash =
node1.execute(privateTransactions.deployPrivateSmartContract(deployContractFor12Again));
privateTransactionVerifier
.validPrivateContractDeployed(contractFor12Again.toString())
.verify(node1, transactionHash);
}
private Address generateContractAddress(
final Address address, final long nonce, final String privacyGroup) {
return Address.privateContractAddress(address, nonce, BytesValue.fromHexString(privacyGroup));
}
final String secondContract = "Event Emitter 2";
private long getNonce(final PantheonNode node, final String privacyGroupId) {
return node.execute(
privateTransactions.getTransactionCount(node.getAddress().toString(), privacyGroupId))
.longValue();
eventEmitterHarness.store(
secondContract,
privateTransactionVerifier.noValidEventReturned(),
privateTransactionVerifier.noValidEventReturned(),
"Alice",
"Bob");
eventEmitterHarness.deploy(secondContract, "Alice", "Bob");
eventEmitterHarness.store(secondContract, "Alice", "Bob");
eventEmitterHarness.get(secondContract, "Alice", "Bob");
}
@After
public void tearDown() {
enclave1.getOrion().stop();
enclave2.getOrion().stop();
enclave3.getOrion().stop();
cluster.stop();
privacyNet.stopPrivacyNet();
}
}

@ -14,17 +14,48 @@ package tech.pegasys.pantheon.controller;
import tech.pegasys.pantheon.crypto.InvalidSEC256K1PrivateKeyStoreException;
import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.util.bytes.Bytes32;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import com.google.common.io.Resources;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class KeyPairUtil {
private static final Logger LOG = LogManager.getLogger();
public static String loadResourceFile(final String resourcePath) {
try {
URL path = KeyPairUtil.class.getClassLoader().getResource(resourcePath);
return Resources.toString(path, StandardCharsets.UTF_8).trim();
} catch (Exception e) {
throw new RuntimeException("Unable to load resource: " + resourcePath, e);
}
}
public static SECP256K1.KeyPair loadKeyPairFromResource(final String resourcePath) {
final SECP256K1.KeyPair keyPair;
String keyData = loadResourceFile(resourcePath);
if (keyData == null || keyData.isEmpty()) {
throw new IllegalArgumentException("Unable to load resource: " + resourcePath);
}
try {
SECP256K1.PrivateKey privateKey =
SECP256K1.PrivateKey.create(Bytes32.fromHexString((keyData)));
keyPair = SECP256K1.KeyPair.create(privateKey);
LOG.info("Loaded keyPair {} from {}", keyPair.getPublicKey().toString(), resourcePath);
return keyPair;
} catch (InvalidSEC256K1PrivateKeyStoreException e) {
throw new IllegalArgumentException("Supplied file does not contain valid keyPair pair.");
}
}
public static SECP256K1.KeyPair loadKeyPair(final File keyFile)
throws IOException, IllegalArgumentException {
try {

@ -0,0 +1,44 @@
/*
* 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 java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
import net.consensys.cava.bytes.Bytes;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class OrionKeyGenerator {
private static final Logger LOG = LogManager.getLogger();
public static KeyPair generateKeys() throws NoSuchAlgorithmException {
final KeyPair keyPair = KeyPairGenerator.getInstance("Ed25519").generateKeyPair();
final PublicKey pubKey = keyPair.getPublic();
final PrivateKey privKey = keyPair.getPrivate();
LOG.debug("pubkey : " + pubKey);
LOG.debug("pubkey bytes: " + Bytes.wrap(pubKey.getEncoded()).toHexString());
LOG.debug("pubkey b64 : " + Base64.getEncoder().encodeToString(pubKey.getEncoded()));
LOG.debug("privkey : " + privKey);
LOG.debug("privkey bytes: " + Bytes.wrap(privKey.getEncoded()).toHexString());
LOG.debug("privkey b64 : " + Base64.getEncoder().encodeToString(privKey.getEncoded()));
return keyPair;
}
}

@ -12,14 +12,23 @@
*/
package tech.pegasys.orion.testutil;
import static java.nio.charset.StandardCharsets.UTF_8;
import static net.consensys.cava.io.file.Files.copyResource;
import java.io.IOException;
import java.nio.file.Path;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
import com.google.common.io.CharSink;
import com.google.common.io.Files;
import net.consensys.orion.cmd.Orion;
import net.consensys.orion.config.Config;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters;
import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters;
public class OrionTestHarnessFactory {
@ -28,14 +37,61 @@ public class OrionTestHarnessFactory {
public static OrionTestHarness create(
final Path tempDir,
final Ed25519PublicKeyParameters pubKey,
final String pubKeyPath,
final Ed25519PrivateKeyParameters privKey,
final String privKeyPath,
final String... othernodes)
throws Exception {
throws IOException {
return create(
tempDir, pubKeyPath, privKeyPath, pubKey.getEncoded(), privKey.getEncoded(), othernodes);
}
public static OrionTestHarness create(
final Path tempDir,
final PublicKey pubKey,
final String pubKeyPath,
final PrivateKey privKey,
final String privKeyPath,
final String... othernodes)
throws IOException {
return create(
tempDir, pubKeyPath, privKeyPath, pubKey.getEncoded(), privKey.getEncoded(), othernodes);
}
private static OrionTestHarness create(
final Path tempDir,
final String pubKeyPath,
final String privKeyPath,
final byte[] encodedPubKey,
final byte[] encodedPrivKey,
final String[] othernodes)
throws IOException {
final Path pubKeyFile = tempDir.resolve(pubKeyPath);
final CharSink pubKeySink = Files.asCharSink(pubKeyFile.toFile(), UTF_8);
pubKeySink.write(Base64.getEncoder().encodeToString(encodedPubKey));
final Path privKeyFile = tempDir.resolve(privKeyPath);
final CharSink privKeySink = Files.asCharSink(privKeyFile.toFile(), UTF_8);
privKeySink.write(Base64.getEncoder().encodeToString(encodedPrivKey));
return create(tempDir, pubKeyFile, privKeyFile, othernodes);
}
public static OrionTestHarness create(
final Path tempDir,
final String pubKeyPath,
final String privKeyPath,
final String... othernodes)
throws IOException {
Path key1pub = copyResource(pubKeyPath, tempDir.resolve(pubKeyPath));
Path key1key = copyResource(privKeyPath, tempDir.resolve(privKeyPath));
return create(tempDir, key1pub, key1key, othernodes);
}
public static OrionTestHarness create(
final Path tempDir, final Path key1pub, final Path key1key, final String... othernodes) {
// @formatter:off
String confString =
"tls=\"off\"\n"

Loading…
Cancel
Save