mirror of
https://github.com/vacp2p/linea-besu.git
synced 2026-01-09 21:17:54 -05:00
[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>
This commit is contained in:
committed by
Eric Kellstrand
parent
fc4f9917b7
commit
e91ba1efea
@@ -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);
|
||||
|
||||
assertEquals("0x", privateTxReceipt.getOutput());
|
||||
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");
|
||||
public class PrivacyClusterAcceptanceTest extends PrivacyAcceptanceTestBase {
|
||||
private static final String CONTRACT_NAME = "Event Emmiter";
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
eventEmitterHarness.deploy(CONTRACT_NAME, "Alice", "Bob");
|
||||
eventEmitterHarness.store(CONTRACT_NAME, "Bob", "Alice");
|
||||
|
||||
final Address contractFor12 =
|
||||
generateContractAddress(node1.getAddress(), nextNonce, privacyGroup12);
|
||||
final String secondContract = "Event Emitter 2";
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
eventEmitterHarness.deploy(CONTRACT_NAME, "Alice", "Bob", "Charlie");
|
||||
eventEmitterHarness.store(CONTRACT_NAME, "Alice", "Bob", "Charlie");
|
||||
|
||||
final Address contractForABC =
|
||||
generateContractAddress(node1.getAddress(), nextNonce, privacyGroup123);
|
||||
final String secondContract = "Event Emitter 2";
|
||||
|
||||
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);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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,30 +12,86 @@
|
||||
*/
|
||||
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 {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger();
|
||||
protected static final String HOST = "127.0.0.1";
|
||||
|
||||
public static OrionTestHarness create(
|
||||
final Path tempDir,
|
||||
final Ed25519PublicKeyParameters pubKey,
|
||||
final String pubKeyPath,
|
||||
final Ed25519PrivateKeyParameters privKey,
|
||||
final String privKeyPath,
|
||||
final String... othernodes)
|
||||
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 Exception {
|
||||
|
||||
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"
|
||||
|
||||
Reference in New Issue
Block a user