Add ATs for on chain privacy with multi tenancy (#1422)

* add ATs for on-chain privacy with multi-tenancy

Signed-off-by: Stefan Pingel <stefan.pingel@consensys.net>
pull/1427/head
Stefan Pingel 4 years ago committed by GitHub
parent 5c0ee9d846
commit 8f80612374
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 6
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfigurationBuilder.java
  3. 4
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java
  4. 9
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/privacy/PrivacyNodeConfiguration.java
  5. 33
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/privacy/PrivacyNodeFactory.java
  6. 15
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/PrivacyCluster.java
  7. 5
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/PrivacyNode.java
  8. 33
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/account/PrivacyAccount.java
  9. 14
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/account/PrivacyAccountResolver.java
  10. 42
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/condition/ExpectUnauthorizedPrivateTransactionReceipt.java
  11. 8
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/condition/ExpectValidPrivateTransactionReceipt.java
  12. 5
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/condition/PrivateTransactionVerifier.java
  13. 15
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/CreateOnChainPrivacyGroupTransaction.java
  14. 24
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/PrivacyTransactions.java
  15. 9
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/RemoveFromOnChainPrivacyGroupTransaction.java
  16. 46
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/privacy/PrivGetTransaction.java
  17. 9
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/privacy/PrivacyRequestFactory.java
  18. 3
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/MultiTenancyAcceptanceTest.java
  19. 58
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/MultiTenancyPrivacyGroup.java
  20. 50
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/MultiTenancyPrivacyNode.java
  21. 3
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/MultiTenancyValidationFailAcceptanceTest.java
  22. 461
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/OnChainMultiTenancyAcceptanceTest.java
  23. 134
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/OnChainPrivacyAcceptanceTest.java
  24. 177
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/OnChainPrivacyAcceptanceTestBase.java
  25. 10
      acceptance-tests/tests/src/test/resources/authentication/auth_priv.toml
  26. 1
      besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java
  27. 6
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  28. 14
      besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java
  29. 3
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java
  30. 20
      testutil/src/main/java/org/hyperledger/orion/testutil/OrionConfiguration.java
  31. 21
      testutil/src/main/java/org/hyperledger/orion/testutil/OrionKeyConfiguration.java
  32. 14
      testutil/src/main/java/org/hyperledger/orion/testutil/OrionTestHarness.java
  33. 51
      testutil/src/main/java/org/hyperledger/orion/testutil/OrionTestHarnessFactory.java

@ -12,6 +12,7 @@ Hyperledger Besu is moving its versioning scheme to [CalVer](https://calver.org/
* Added `debug_standardTraceBadBlockToFile` JSON-RPC API. This API is similar to `debug_standardTraceBlockToFile`, but can be used to obtain info about a block which has been rejected as invalid. [\#1403](https://github.com/hyperledger/besu/pull/1403)
* Added support for EIP-2929 to YOLOv2. [#1387](https://github.com/hyperledger/besu/pull/1387)
* Added `--start-block` and `--end-block` to the `blocks import` subcommand [\#1399](https://github.com/hyperledger/besu/pull/1399)
* Added support for multi-tenancy when using the early access feature of [onchain privacy group management](https://besu.hyperledger.org/en/stable/Concepts/Privacy/Onchain-PrivacyGroups/)
* Fixed memory leak in eth/65 subprotocol behavior. It is now enabled by default. [\#1420](https://github.com/hyperledger/besu/pull/1420), [#1348](https://github.com/hyperledger/besu/pull/1348), [#1321](https://github.com/hyperledger/besu/pull/1321)
### Bug Fixes

@ -47,7 +47,7 @@ public class BesuNodeConfigurationBuilder {
private WebSocketConfiguration webSocketConfiguration = WebSocketConfiguration.createDefault();
private MetricsConfiguration metricsConfiguration = MetricsConfiguration.builder().build();
private Optional<PermissioningConfiguration> permissioningConfiguration = Optional.empty();
private Optional<String> keyFilePath = Optional.empty();
private String keyFilePath = null;
private boolean devMode = true;
private GenesisConfigurationProvider genesisConfigProvider = ignore -> Optional.empty();
private Boolean p2pEnabled = true;
@ -212,7 +212,7 @@ public class BesuNodeConfigurationBuilder {
}
public BesuNodeConfigurationBuilder keyFilePath(final String keyFilePath) {
this.keyFilePath = Optional.of(keyFilePath);
this.keyFilePath = keyFilePath;
return this;
}
@ -293,7 +293,7 @@ public class BesuNodeConfigurationBuilder {
webSocketConfiguration,
metricsConfiguration,
permissioningConfiguration,
keyFilePath,
Optional.ofNullable(keyFilePath),
devMode,
genesisConfigProvider,
p2pEnabled,

@ -195,13 +195,15 @@ public class BesuNodeFactory {
final String name,
final String enclaveUrl,
final String authFile,
final String privTransactionSigningKey)
final String privTransactionSigningKey,
final boolean enableOnChainPrivacy)
throws IOException, URISyntaxException {
final PrivacyParameters.Builder privacyParametersBuilder = new PrivacyParameters.Builder();
final PrivacyParameters privacyParameters =
privacyParametersBuilder
.setMultiTenancyEnabled(true)
.setEnabled(true)
.setOnchainPrivacyGroupsEnabled(enableOnChainPrivacy)
.setStorageProvider(new InMemoryPrivacyStorageProvider())
.setEnclaveFactory(new EnclaveFactory(Vertx.vertx()))
.setEnclaveUrl(URI.create(enclaveUrl))

@ -23,23 +23,26 @@ public class PrivacyNodeConfiguration {
private final boolean isOnchainPrivacyGroupEnabled;
private final BesuNodeConfiguration besuConfig;
private final OrionKeyConfiguration orionConfig;
private final boolean isMultitenancyEnabled;
PrivacyNodeConfiguration(
final int privacyAddress,
final BesuNodeConfiguration besuConfig,
final OrionKeyConfiguration orionConfig) {
this(privacyAddress, false, besuConfig, orionConfig);
this(privacyAddress, false, false, besuConfig, orionConfig);
}
PrivacyNodeConfiguration(
final int privacyAddress,
final boolean isOnchainPrivacyGroupEnabled,
final boolean isMultitenancyEnabled,
final BesuNodeConfiguration besuConfig,
final OrionKeyConfiguration orionConfig) {
this.privacyAddress = privacyAddress;
this.isOnchainPrivacyGroupEnabled = isOnchainPrivacyGroupEnabled;
this.besuConfig = besuConfig;
this.orionConfig = orionConfig;
this.isMultitenancyEnabled = isMultitenancyEnabled;
}
public int getPrivacyAddress() {
@ -50,6 +53,10 @@ public class PrivacyNodeConfiguration {
return isOnchainPrivacyGroupEnabled;
}
public boolean isMultitenancyEnabled() {
return isMultitenancyEnabled;
}
public BesuNodeConfiguration getBesuConfig() {
return besuConfig;
}

@ -23,6 +23,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccount;
import org.hyperledger.orion.testutil.OrionKeyConfiguration;
import java.io.IOException;
import java.net.URISyntaxException;
import io.vertx.core.Vertx;
@ -60,7 +61,7 @@ public class PrivacyNodeFactory {
.keyFilePath(privacyAccount.getPrivateKeyPath())
.build(),
new OrionKeyConfiguration(
privacyAccount.getEnclaveKeyPath(), privacyAccount.getEnclavePrivateKeyPath())));
privacyAccount.getEnclaveKeyPaths(), privacyAccount.getEnclavePrivateKeyPaths())));
}
public PrivacyNode createPrivateTransactionEnabledNode(
@ -82,7 +83,7 @@ public class PrivacyNodeFactory {
.webSocketEnabled()
.build(),
new OrionKeyConfiguration(
privacyAccount.getEnclaveKeyPath(), privacyAccount.getEnclavePrivateKeyPath())));
privacyAccount.getEnclaveKeyPaths(), privacyAccount.getEnclavePrivateKeyPaths())));
}
public PrivacyNode createIbft2NodePrivacyMiningEnabled(
@ -115,17 +116,27 @@ public class PrivacyNodeFactory {
.enablePrivateTransactions()
.build(),
new OrionKeyConfiguration(
privacyAccount.getEnclaveKeyPath(), privacyAccount.getEnclavePrivateKeyPath())));
privacyAccount.getEnclaveKeyPaths(), privacyAccount.getEnclavePrivateKeyPaths())));
}
public PrivacyNode createOnChainPrivacyGroupEnabledMinerNode(
final String name, final PrivacyAccount privacyAccount, final int privacyAddress)
throws IOException {
final String name,
final PrivacyAccount privacyAccount,
final int privacyAddress,
final boolean multiTenancyEnabled)
throws IOException, URISyntaxException {
final BesuNodeConfigurationBuilder besuNodeConfigurationBuilder =
new BesuNodeConfigurationBuilder();
if (multiTenancyEnabled) {
besuNodeConfigurationBuilder.jsonRpcAuthenticationConfiguration(
"authentication/auth_priv.toml");
}
return create(
new PrivacyNodeConfiguration(
privacyAddress,
true,
new BesuNodeConfigurationBuilder()
multiTenancyEnabled,
besuNodeConfigurationBuilder
.name(name)
.miningEnabled()
.jsonRpcEnabled()
@ -134,16 +145,20 @@ public class PrivacyNodeFactory {
.keyFilePath(privacyAccount.getPrivateKeyPath())
.build(),
new OrionKeyConfiguration(
privacyAccount.getEnclaveKeyPath(), privacyAccount.getEnclavePrivateKeyPath())));
privacyAccount.getEnclaveKeyPaths(), privacyAccount.getEnclavePrivateKeyPaths())));
}
public PrivacyNode createOnChainPrivacyGroupEnabledNode(
final String name, final PrivacyAccount privacyAccount, final int privacyAddress)
final String name,
final PrivacyAccount privacyAccount,
final int privacyAddress,
final boolean multiTenancyEnabled)
throws IOException {
return create(
new PrivacyNodeConfiguration(
privacyAddress,
true,
multiTenancyEnabled,
new BesuNodeConfigurationBuilder()
.name(name)
.jsonRpcEnabled()
@ -152,6 +167,6 @@ public class PrivacyNodeFactory {
.webSocketEnabled()
.build(),
new OrionKeyConfiguration(
privacyAccount.getEnclaveKeyPath(), privacyAccount.getEnclavePrivateKeyPath())));
privacyAccount.getEnclaveKeyPaths(), privacyAccount.getEnclavePrivateKeyPaths())));
}
}

@ -48,6 +48,15 @@ public class PrivacyCluster {
}
public void start(final List<PrivacyNode> nodes) {
startNodes(nodes);
awaitPeerCount(nodes);
}
public void startNodes(final PrivacyNode... nodes) {
startNodes(Arrays.asList(nodes));
}
public void startNodes(final List<PrivacyNode> nodes) {
if (nodes.isEmpty()) {
throw new IllegalArgumentException("Can't start a cluster with no nodes");
}
@ -59,7 +68,13 @@ public class PrivacyCluster {
nodes.stream()
.filter(node -> bootNode.map(boot -> boot != node).orElse(true))
.forEach(this::startNode);
}
public void awaitPeerCount(final PrivacyNode... nodes) {
awaitPeerCount(Arrays.asList(nodes));
}
public void awaitPeerCount(final List<PrivacyNode> nodes) {
for (final PrivacyNode node : nodes) {
LOG.info("Awaiting peer discovery for node {}", node.getName());
node.awaitPeerDiscovery(net.awaitPeerCount(nodes.size() - 1));

@ -70,6 +70,7 @@ public class PrivacyNode implements AutoCloseable {
private final BesuNode besu;
private final Vertx vertx;
private final boolean isOnchainPrivacyEnabled;
private final boolean isMultitenancyEnabled;
public PrivacyNode(final PrivacyNodeConfiguration privacyConfiguration, final Vertx vertx)
throws IOException {
@ -80,6 +81,7 @@ public class PrivacyNode implements AutoCloseable {
final BesuNodeConfiguration besuConfig = privacyConfiguration.getBesuConfig();
isOnchainPrivacyEnabled = privacyConfiguration.isOnchainPrivacyGroupEnabled();
isMultitenancyEnabled = privacyConfiguration.isMultitenancyEnabled();
this.besu =
new BesuNode(
@ -176,8 +178,9 @@ public class PrivacyNode implements AutoCloseable {
.setPrivateKeyPath(KeyPairUtil.getDefaultKeyFile(besu.homeDirectory()).toPath())
.setEnclaveFactory(new EnclaveFactory(vertx))
.setOnchainPrivacyGroupsEnabled(isOnchainPrivacyEnabled)
.setMultiTenancyEnabled(isMultitenancyEnabled)
.build();
} catch (IOException e) {
} catch (final IOException e) {
throw new RuntimeException();
}
besu.setPrivacyParameters(privacyParameters);

@ -16,22 +16,33 @@ package org.hyperledger.besu.tests.acceptance.dsl.privacy.account;
import java.io.File;
import java.net.URL;
import java.util.Arrays;
public class PrivacyAccount {
private final URL privateKeyPath;
private final URL enclaveKeyPath;
private final URL enclavePrivateKeyPath;
private final URL[] enclaveKeyPaths;
private final URL[] enclavePrivateKeyPaths;
private PrivacyAccount(
final URL privateKeyPath, final URL enclavePublicKeyPath, final URL enclavePrivateKeyPath) {
final URL privateKeyPath,
final URL[] enclavePublicKeyPaths,
final URL[] enclavePrivateKeyPaths) {
this.privateKeyPath = privateKeyPath;
this.enclaveKeyPath = enclavePublicKeyPath;
this.enclavePrivateKeyPath = enclavePrivateKeyPath;
this.enclaveKeyPaths = enclavePublicKeyPaths;
this.enclavePrivateKeyPaths = enclavePrivateKeyPaths;
}
public static PrivacyAccount create(
final URL privateKeyPath, final URL enclavePublicKeyPath, final URL enclavePrivateKeyPath) {
return new PrivacyAccount(
privateKeyPath, new URL[] {enclavePublicKeyPath}, new URL[] {enclavePrivateKeyPath});
}
public static PrivacyAccount create(
final URL privateKeyPath,
final URL[] enclavePublicKeyPath,
final URL[] enclavePrivateKeyPath) {
return new PrivacyAccount(privateKeyPath, enclavePublicKeyPath, enclavePrivateKeyPath);
}
@ -39,12 +50,16 @@ public class PrivacyAccount {
return toStringResource(privateKeyPath);
}
public String getEnclaveKeyPath() {
return toStringResource(enclaveKeyPath);
public String[] getEnclaveKeyPaths() {
return Arrays.stream(enclaveKeyPaths)
.map(path -> toStringResource(path))
.toArray(String[]::new);
}
public String getEnclavePrivateKeyPath() {
return toStringResource(enclavePrivateKeyPath);
public String[] getEnclavePrivateKeyPaths() {
return Arrays.stream(enclavePrivateKeyPaths)
.map(path -> toStringResource(path))
.toArray(String[]::new);
}
private String toStringResource(final URL path) {

@ -37,6 +37,20 @@ public class PrivacyAccountResolver {
resolveResource("orion_key_2.pub"),
resolveResource("orion_key_2.key"));
public static final PrivacyAccount MULTI_TENANCY =
PrivacyAccount.create(
resolveResource("key"),
new URL[] {
resolveResource("orion_key_0.pub"),
resolveResource("orion_key_1.pub"),
resolveResource("orion_key_2.pub")
},
new URL[] {
resolveResource("orion_key_0.key"),
resolveResource("orion_key_1.key"),
resolveResource("orion_key_2.key")
});
private static URL resolveResource(final String resource) {
return PrivacyAccountResolver.class.getClassLoader().getResource(resource);
}

@ -0,0 +1,42 @@
/*
* Copyright 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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.tests.acceptance.dsl.privacy.condition;
import static org.assertj.core.api.Assertions.assertThat;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.transaction.PrivacyTransactions;
import org.web3j.protocol.exceptions.ClientConnectionException;
public class ExpectUnauthorizedPrivateTransactionReceipt implements PrivateCondition {
private final PrivacyTransactions transactions;
private final String transactionHash;
public ExpectUnauthorizedPrivateTransactionReceipt(
final PrivacyTransactions transactions, final String transactionHash) {
this.transactions = transactions;
this.transactionHash = transactionHash;
}
@Override
public void verify(final PrivacyNode node) {
try {
node.execute(transactions.getPrivateTransactionReceipt(transactionHash));
} catch (final ClientConnectionException e) {
assertThat(e.getMessage()).contains("Unauthorized");
}
}
}

@ -43,12 +43,8 @@ public class ExpectValidPrivateTransactionReceipt implements PrivateCondition {
assertThat(actualReceipt)
.usingRecursiveComparison()
.ignoringFields(
"commitmentHash",
"logs",
"blockHash",
"blockNumber",
"logsBloom",
"transactionIndex") // TODO: The fields blockHash, blockNumber, logsBloom and
"commitmentHash", "logs", "blockHash", "blockNumber", "logsBloom", "transactionIndex")
// TODO: The fields blockHash, blockNumber, logsBloom and
// transactionIndex have to be ignored as the class
// org.web3j.protocol.besu.response.privacy.PrivateTransactionReceipt does not contain these
// fields. Once web3j has been updated these ignores can be removed.

@ -61,6 +61,11 @@ public class PrivateTransactionVerifier {
.map(PrivacyNode::getEnclaveKey)
.map(Base64String::wrap)
.collect(Collectors.toList());
return onChainPrivacyGroupExists(privacyGroupId, membersEnclaveKeys);
}
public ExpectValidOnChainPrivacyGroupCreated onChainPrivacyGroupExists(
final String privacyGroupId, final List<Base64String> membersEnclaveKeys) {
final OnChainPrivacyGroup expectedGroup =
new OnChainPrivacyGroup(privacyGroupId, membersEnclaveKeys);

@ -20,28 +20,25 @@ import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.PrivacyRequestFactory.PrivxCreatePrivacyGroupResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class CreateOnChainPrivacyGroupTransaction
implements Transaction<PrivxCreatePrivacyGroupResponse> {
private final PrivacyNode creator;
private final List<String> addresses;
private final String privateFrom;
public CreateOnChainPrivacyGroupTransaction(
final PrivacyNode creator, final PrivacyNode... nodes) {
CreateOnChainPrivacyGroupTransaction(
final PrivacyNode creator, final String privateFrom, final List<String> addresses) {
this.creator = creator;
this.addresses =
Arrays.stream(nodes)
.map(n -> n.getOrion().getDefaultPublicKey())
.collect(Collectors.toList());
this.addresses = addresses;
this.privateFrom = privateFrom;
}
@Override
public PrivxCreatePrivacyGroupResponse execute(final NodeRequests node) {
try {
return node.privacy().privxCreatePrivacyGroup(creator, addresses);
return node.privacy().privxCreatePrivacyGroup(creator, privateFrom, addresses);
} catch (final IOException e) {
throw new RuntimeException(e);
}

@ -22,6 +22,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.EeaSendRawT
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.PrivCallTransaction;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.PrivGetCodeTransaction;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.PrivGetLogsTransaction;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.PrivGetTransaction;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.filter.PrivGetFilterChangesTransaction;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.filter.PrivGetFilterLogsTransaction;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.filter.PrivNewFilterTransaction;
@ -45,8 +46,17 @@ public class PrivacyTransactions {
}
public CreateOnChainPrivacyGroupTransaction createOnChainPrivacyGroup(
final PrivacyNode creator, final PrivacyNode... nodes) {
return new CreateOnChainPrivacyGroupTransaction(creator, nodes);
final PrivacyNode creator,
final String privateFrom,
final List<String> addresses,
final String token) {
creator.getBesu().useAuthenticationTokenInHeaderForJsonRpc(token);
return new CreateOnChainPrivacyGroupTransaction(creator, privateFrom, addresses);
}
public CreateOnChainPrivacyGroupTransaction createOnChainPrivacyGroup(
final PrivacyNode creator, final String privateFrom, final List<String> addresses) {
return new CreateOnChainPrivacyGroupTransaction(creator, privateFrom, addresses);
}
public AddToOnChainPrivacyGroupTransaction addToPrivacyGroup(
@ -80,6 +90,10 @@ public class PrivacyTransactions {
return new PrivCallTransaction(privacyGroupId, contract, encoded);
}
public PrivGetTransaction privGetTransaction(final String transactionHash) {
return new PrivGetTransaction(transactionHash);
}
public PrivGetCodeTransaction privGetCode(
final String privacyGroupId, final Address contractAddress, final String blockParameter) {
return new PrivGetCodeTransaction(privacyGroupId, contractAddress, blockParameter);
@ -92,11 +106,11 @@ public class PrivacyTransactions {
public RemoveFromOnChainPrivacyGroupTransaction removeFromPrivacyGroup(
final String privacyGroupId,
final PrivacyNode remover,
final String remover,
final Credentials signer,
final PrivacyNode nodeToRemove) {
final String memberToRemove) {
return new RemoveFromOnChainPrivacyGroupTransaction(
privacyGroupId, remover, signer, nodeToRemove);
privacyGroupId, remover, signer, memberToRemove);
}
public EeaSendRawTransactionTransaction sendRawTransaction(final String transaction) {

@ -14,7 +14,6 @@
*/
package org.hyperledger.besu.tests.acceptance.dsl.privacy.transaction;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.NodeRequests;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
@ -25,19 +24,19 @@ import org.web3j.utils.Base64String;
public class RemoveFromOnChainPrivacyGroupTransaction implements Transaction<String> {
private final Base64String privacyGroupId;
private final PrivacyNode remover;
private final String remover;
private final String toRemove;
private final Credentials signer;
public RemoveFromOnChainPrivacyGroupTransaction(
final String privacyGroupId,
final PrivacyNode remover,
final String remover,
final Credentials signer,
final PrivacyNode toRemove) {
final String toRemove) {
this.privacyGroupId = Base64String.wrap(privacyGroupId);
this.remover = remover;
this.signer = signer;
this.toRemove = toRemove.getOrion().getDefaultPublicKey();
this.toRemove = toRemove;
}
@Override

@ -0,0 +1,46 @@
/*
* Copyright 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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy;
import static org.assertj.core.api.Assertions.assertThat;
import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.NodeRequests;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
import java.io.IOException;
public class PrivGetTransaction
implements Transaction<PrivacyRequestFactory.GetPrivateTransactionResponse> {
private final String transactionHash;
public PrivGetTransaction(final String transactionHash) {
this.transactionHash = transactionHash;
}
@Override
public PrivacyRequestFactory.GetPrivateTransactionResponse execute(final NodeRequests node) {
try {
final PrivacyRequestFactory.GetPrivateTransactionResponse response =
node.privacy().privGetPrivateTransaction(Hash.fromHexString(transactionHash)).send();
assertThat(response).as("check response is not null").isNotNull();
assertThat(response.getResult()).as("check result in response isn't null").isNotNull();
return response;
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
}

@ -164,7 +164,7 @@ public class PrivacyRequestFactory {
public String privxRemoveFromPrivacyGroup(
final Base64String privacyGroupId,
final PrivacyNode remover,
final String removerTenant,
final Credentials signer,
final String toRemove)
throws IOException {
@ -184,7 +184,7 @@ public class PrivacyRequestFactory {
BigInteger.valueOf(3000000),
Address.ONCHAIN_PRIVACY_PROXY.toHexString(),
payload.toHexString(),
Base64String.wrap(remover.getEnclaveKey()),
Base64String.wrap(removerTenant),
privacyGroupId,
org.web3j.utils.Restriction.RESTRICTED);
@ -237,7 +237,8 @@ public class PrivacyRequestFactory {
}
public PrivxCreatePrivacyGroupResponse privxCreatePrivacyGroup(
final PrivacyNode creator, final List<String> addresses) throws IOException {
final PrivacyNode creator, final String privateFrom, final List<String> addresses)
throws IOException {
final byte[] bytes = new byte[32];
secureRandom.nextBytes(bytes);
@ -254,7 +255,7 @@ public class PrivacyRequestFactory {
BigInteger.valueOf(3000000),
Address.ONCHAIN_PRIVACY_PROXY.toHexString(),
payload.toHexString(),
Base64String.wrap(creator.getEnclaveKey()),
Base64String.wrap(privateFrom),
Base64String.wrap(privacyGroupId.toArrayUnsafe()),
org.web3j.utils.Restriction.RESTRICTED);

@ -82,7 +82,8 @@ public class MultiTenancyAcceptanceTest extends AcceptanceTestBase {
"node1",
"http://127.0.0.1:" + wireMockRule.port(),
"authentication/auth_priv.toml",
"authentication/auth_priv_key");
"authentication/auth_priv_key",
false);
multiTenancyCluster.start(node);
final String token =
node.execute(permissioningTransactions.createSuccessfulLogin("user", "pegasys"));

@ -0,0 +1,58 @@
/*
* Copyright 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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.tests.acceptance.privacy.multitenancy;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class MultiTenancyPrivacyGroup {
private final Map<MultiTenancyPrivacyNode, List<String>> map;
public MultiTenancyPrivacyGroup() {
this.map = new HashMap<>();
}
public MultiTenancyPrivacyGroup addNodeWithTenants(
final MultiTenancyPrivacyNode privacyNode, final List<String> tenants) {
map.put(privacyNode, tenants);
return this;
}
public List<MultiTenancyPrivacyNode> getPrivacyNodes() {
return map.keySet().stream().collect(Collectors.toList());
}
public List<String> getTenantsForNode(final MultiTenancyPrivacyNode privacyNode) {
return map.get(privacyNode);
}
public List<String> getTenants() {
return map.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
}
public PrivacyNode getGroupCreatingPrivacyNode() {
return getPrivacyNodes().get(0).getPrivacyNode();
}
public String getGroupCreatingTenant() {
return getPrivacyNodes().get(0).getTenants().get(0);
}
}

@ -0,0 +1,50 @@
/*
* Copyright 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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.tests.acceptance.privacy.multitenancy;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class MultiTenancyPrivacyNode {
private final PrivacyNode privacyNode;
private final Map<String, String> tenantToTokenMap;
public MultiTenancyPrivacyNode(final PrivacyNode privacyNode) {
this.privacyNode = privacyNode;
this.tenantToTokenMap = new HashMap<>();
}
public MultiTenancyPrivacyNode addTenantWithToken(final String tenant, final String token) {
tenantToTokenMap.put(tenant, token);
return this;
}
public List<String> getTenants() {
return tenantToTokenMap.keySet().stream().collect(Collectors.toList());
}
public String getTokenForTenant(final String tenant) {
return tenantToTokenMap.get(tenant);
}
public PrivacyNode getPrivacyNode() {
return privacyNode;
}
}

@ -76,7 +76,8 @@ public class MultiTenancyValidationFailAcceptanceTest extends AcceptanceTestBase
"node1",
"http://127.0.0.1:" + wireMockRule.port(),
"authentication/auth_priv.toml",
"authentication/auth_priv_key");
"authentication/auth_priv_key",
false);
multiTenancyCluster.start(node);
final String token =

@ -0,0 +1,461 @@
/*
* Copyright 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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.tests.acceptance.privacy.multitenancy;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.contract.CallPrivateSmartContractFunction;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.transaction.CreateOnChainPrivacyGroupTransaction;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.util.LogFilterJsonParameter;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.perm.PermissioningTransactions;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.PrivacyRequestFactory;
import org.hyperledger.besu.tests.web3j.generated.EventEmitter;
import org.hyperledger.besu.tests.web3j.privacy.OnChainPrivacyAcceptanceTestBase;
import java.math.BigInteger;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.web3j.crypto.Credentials;
import org.web3j.protocol.besu.response.privacy.PrivateTransactionReceipt;
import org.web3j.protocol.core.methods.response.EthCall;
import org.web3j.utils.Base64String;
public class OnChainMultiTenancyAcceptanceTest extends OnChainPrivacyAcceptanceTestBase {
private static final String eventEmitterDeployed =
"0x6080604052600436106100565763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416633fa4f245811461005b5780636057361d1461008257806367e404ce146100ae575b600080fd5b34801561006757600080fd5b506100706100ec565b60408051918252519081900360200190f35b34801561008e57600080fd5b506100ac600480360360208110156100a557600080fd5b50356100f2565b005b3480156100ba57600080fd5b506100c3610151565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b60025490565b604080513381526020810183905281517fc9db20adedc6cf2b5d25252b101ab03e124902a73fcb12b753f3d1aaa2d8f9f5929181900390910190a16002556001805473ffffffffffffffffffffffffffffffffffffffff191633179055565b60015473ffffffffffffffffffffffffffffffffffffffff169056fea165627a7a72305820c7f729cb24e05c221f5aa913700793994656f233fe2ce3b9fd9a505ea17e8d8a0029";
private static final PermissioningTransactions permissioningTransactions =
new PermissioningTransactions();
private static final long VALUE_SET = 10L;
private PrivacyNode alice;
private MultiTenancyPrivacyNode aliceMultiTenancyPrivacyNode;
@Before
public void setUp() throws Exception {
alice =
privacyBesu.createOnChainPrivacyGroupEnabledMinerNode(
"node1", PrivacyAccountResolver.MULTI_TENANCY, Address.PRIVACY, true);
final BesuNode aliceBesu = alice.getBesu();
privacyCluster.startNodes(alice);
final String alice1Token =
aliceBesu.execute(permissioningTransactions.createSuccessfulLogin("user", "pegasys"));
aliceBesu.useAuthenticationTokenInHeaderForJsonRpc(alice1Token);
final String alice2Token =
aliceBesu.execute(permissioningTransactions.createSuccessfulLogin("user2", "Password2"));
final String alice3Token =
aliceBesu.execute(permissioningTransactions.createSuccessfulLogin("user3", "Password3"));
privacyCluster.awaitPeerCount(alice);
final String alice1EnclaveKey = alice.getOrion().getPublicKeys().get(0);
final String alice2EnclaveKey = alice.getOrion().getPublicKeys().get(1);
final String alice3EnclaveKey = alice.getOrion().getPublicKeys().get(2);
aliceMultiTenancyPrivacyNode = new MultiTenancyPrivacyNode(alice);
aliceMultiTenancyPrivacyNode
.addTenantWithToken(alice1EnclaveKey, alice1Token)
.addTenantWithToken(alice2EnclaveKey, alice2Token)
.addTenantWithToken(alice3EnclaveKey, alice3Token);
}
@After
public void tearDown() {
privacyCluster.close();
}
@Test
public void createPrivacyGroup() {
createOnChainPrivacyGroup(alice);
}
@Test
public void createPrivacyGroupWithAllTenants() {
final MultiTenancyPrivacyGroup privacyGroup = new MultiTenancyPrivacyGroup();
privacyGroup.addNodeWithTenants(
aliceMultiTenancyPrivacyNode, aliceMultiTenancyPrivacyNode.getTenants());
createOnChainPrivacyGroup(privacyGroup);
}
@Test
public void noAccessWhenNotAMember() {
final MultiTenancyPrivacyGroup twoTenantsFromAlice = new MultiTenancyPrivacyGroup();
final List<String> tenants = aliceMultiTenancyPrivacyNode.getTenants();
final String removedTenant = tenants.remove(tenants.size() - 1);
twoTenantsFromAlice.addNodeWithTenants(aliceMultiTenancyPrivacyNode, tenants);
final String privacyGroupId = createOnChainPrivacyGroup(twoTenantsFromAlice);
final MultiTenancyPrivacyNode multiTenancyPrivacyNode =
twoTenantsFromAlice.getPrivacyNodes().get(0);
final String tenant = tenants.get(0);
final PrivacyNode privacyNode = multiTenancyPrivacyNode.getPrivacyNode();
final BesuNode privacyNodeBesu = privacyNode.getBesu();
privacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
multiTenancyPrivacyNode.getTokenForTenant(tenant));
final EventEmitter eventEmitter =
privacyNode.execute(
privateContractTransactions.createSmartContractWithPrivacyGroupId(
EventEmitter.class,
privacyNode.getTransactionSigningKey(),
POW_CHAIN_ID,
tenant,
privacyGroupId));
final String transactionHash = getContractDeploymentCommitmentHash(eventEmitter);
// check that a member can get the transaction receipt
privacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
multiTenancyPrivacyNode.getTokenForTenant(tenant));
privacyNode.verify(
privateTransactionVerifier.validPrivateTransactionReceipt(
transactionHash,
(PrivateTransactionReceipt) eventEmitter.getTransactionReceipt().get()));
assertThat(
privacyNode
.execute(
privacyTransactions.privGetCode(
privacyGroupId,
Address.fromHexString(eventEmitter.getContractAddress()),
"latest"))
.toHexString())
.isEqualTo(eventEmitterDeployed);
// check that getting the transaction receipt does not work if you are not a member
privacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
multiTenancyPrivacyNode.getTokenForTenant(removedTenant));
privacyNode.verify(
privateTransactionVerifier.noPrivateTransactionReceipt(
transactionHash)); // returning null because the RPC is using the enclave key
// check that getting the code of the event emitter does not work when you are not a member
assertThatThrownBy(
() ->
privacyNode.execute(
privacyTransactions.privGetCode(
privacyGroupId,
Address.fromHexString(eventEmitter.getContractAddress()),
"latest")))
.hasMessageContaining("Unauthorized");
final LogFilterJsonParameter filterParameter =
new LogFilterJsonParameter(
"earliest",
"latest",
List.of(eventEmitter.getContractAddress()),
Collections.emptyList(),
null);
// create a valid filter
privacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
multiTenancyPrivacyNode.getTokenForTenant(tenant));
final String filterId =
privacyNode.execute(privacyTransactions.newFilter(privacyGroupId, filterParameter));
privacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
multiTenancyPrivacyNode.getTokenForTenant(tenant));
final CallPrivateSmartContractFunction storeTransaction =
privateContractTransactions.callSmartContractWithPrivacyGroupId(
eventEmitter.getContractAddress(),
eventEmitter.store(BigInteger.valueOf(VALUE_SET)).encodeFunctionCall(),
privacyNode.getTransactionSigningKey(),
POW_CHAIN_ID,
tenant,
privacyGroupId);
final String storeTransactionHash = privacyNode.execute(storeTransaction);
privacyNode.execute(privacyTransactions.getPrivateTransactionReceipt(storeTransactionHash));
// check that getting the filter changes works for a member
assertThat(privacyNode.execute(privacyTransactions.getFilterChanges(privacyGroupId, filterId)))
.hasSize(1);
// check that getting the filter changes does not work if you are not a member
privacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
multiTenancyPrivacyNode.getTokenForTenant(removedTenant));
assertThatThrownBy(
() ->
privacyNode.execute(privacyTransactions.getFilterChanges(privacyGroupId, filterId)))
.hasMessageContaining("Unauthorized");
// check that getting the filter logs works for a member
privacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
multiTenancyPrivacyNode.getTokenForTenant(tenant));
assertThat(privacyNode.execute(privacyTransactions.getFilterLogs(privacyGroupId, filterId)))
.hasSize(3); // create privacy group, deploy event emitter, store on event emitter
// check that getting the filter logs does not work if you are not a member
privacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
multiTenancyPrivacyNode.getTokenForTenant(removedTenant));
assertThatThrownBy(
() -> privacyNode.execute(privacyTransactions.getFilterLogs(privacyGroupId, filterId)))
.hasMessageContaining("Unauthorized");
// check that getting the logs works for a member
privacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
multiTenancyPrivacyNode.getTokenForTenant(tenant));
assertThat(
privacyNode.execute(privacyTransactions.privGetLogs(privacyGroupId, filterParameter)))
.hasSize(3); // create privacy group, deploy event emitter, store on event emitter
// check that getting the logs does not work if you are not a member
privacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
multiTenancyPrivacyNode.getTokenForTenant(removedTenant));
assertThatThrownBy(
() ->
privacyNode.execute(
privacyTransactions.privGetLogs(privacyGroupId, filterParameter)))
.hasMessageContaining("Unauthorized");
final List<Base64String> base64StringList =
tenants.stream().map(Base64String::wrap).collect(Collectors.toList());
// check that a member can find the on-chain privacy group
privacyNode
.getBesu()
.useAuthenticationTokenInHeaderForJsonRpc(
multiTenancyPrivacyNode.getTokenForTenant(tenant));
final List<PrivacyRequestFactory.OnChainPrivacyGroup> group =
privacyNode.execute(
privacyTransactions.findOnChainPrivacyGroup(Base64String.unwrapList(base64StringList)));
assertThat(group.size()).isEqualTo(1);
assertThat(group.get(0).getMembers()).containsAll(base64StringList).hasSize(2);
// check that when you are not a member you cannot find the privacy group
privacyNode
.getBesu()
.useAuthenticationTokenInHeaderForJsonRpc(
multiTenancyPrivacyNode.getTokenForTenant(removedTenant));
assertThatThrownBy(
() ->
privacyNode.execute(
privacyTransactions.findOnChainPrivacyGroup(
Base64String.unwrapList(base64StringList))))
.hasMessageContaining("Error finding onchain privacy group");
// check that a member can do a priv_call
privacyNode
.getBesu()
.useAuthenticationTokenInHeaderForJsonRpc(
multiTenancyPrivacyNode.getTokenForTenant(tenant));
final EthCall readValue =
privacyNode.execute(
privacyTransactions.privCall(
privacyGroupId, eventEmitter, eventEmitter.value().encodeFunctionCall()));
assertThat(new BigInteger(readValue.getValue().substring(2), 16))
.isEqualByComparingTo(BigInteger.valueOf(VALUE_SET));
// check that when you are not a member you cannot do a priv_call
privacyNode
.getBesu()
.useAuthenticationTokenInHeaderForJsonRpc(
multiTenancyPrivacyNode.getTokenForTenant(removedTenant));
assertThatThrownBy(
() ->
privacyNode.execute(
privacyTransactions.privCall(
privacyGroupId, eventEmitter, eventEmitter.value().encodeFunctionCall())))
.hasMessageContaining("Unauthorized");
// check that a member can do a priv_getTransaction
privacyNode
.getBesu()
.useAuthenticationTokenInHeaderForJsonRpc(
multiTenancyPrivacyNode.getTokenForTenant(tenant));
final PrivacyRequestFactory.GetPrivateTransactionResponse privTransaction =
privacyNode.execute(privacyTransactions.privGetTransaction(storeTransactionHash));
assertThat(privTransaction.getResult().getPrivacyGroupId()).isEqualTo(privacyGroupId);
// check that when you are not a member you cannot do a priv_getTransaction
privacyNode
.getBesu()
.useAuthenticationTokenInHeaderForJsonRpc(
multiTenancyPrivacyNode.getTokenForTenant(removedTenant));
assertThatThrownBy(
() -> privacyNode.execute(privacyTransactions.privGetTransaction(storeTransactionHash)))
.hasMessageContaining(
"Expecting actual not to be null"); // TODO: returning null because the RPC is using the
// enclave key
}
@Test
public void removedMemberCannotGetFilterChanges() {
final MultiTenancyPrivacyGroup allTenantsFromAlice = new MultiTenancyPrivacyGroup();
final List<String> tenants = aliceMultiTenancyPrivacyNode.getTenants();
allTenantsFromAlice.addNodeWithTenants(aliceMultiTenancyPrivacyNode, tenants);
final String privacyGroupId = createOnChainPrivacyGroup(allTenantsFromAlice);
final MultiTenancyPrivacyNode multiTenancyPrivacyNode =
allTenantsFromAlice.getPrivacyNodes().get(0);
final String groupCreatingTenant = allTenantsFromAlice.getGroupCreatingTenant();
final String tenantToBeRemoved =
tenants.stream().filter(t -> !t.equals(groupCreatingTenant)).findFirst().orElseThrow();
final PrivacyNode groupCreatingPrivacyNode = allTenantsFromAlice.getGroupCreatingPrivacyNode();
final BesuNode groupCreatingPrivacyNodeBesu = groupCreatingPrivacyNode.getBesu();
groupCreatingPrivacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
multiTenancyPrivacyNode.getTokenForTenant(groupCreatingTenant));
final EventEmitter eventEmitter =
groupCreatingPrivacyNode.execute(
privateContractTransactions.createSmartContractWithPrivacyGroupId(
EventEmitter.class,
groupCreatingPrivacyNode.getTransactionSigningKey(),
POW_CHAIN_ID,
groupCreatingTenant,
privacyGroupId));
final LogFilterJsonParameter filterParameter =
new LogFilterJsonParameter(
"earliest",
"latest",
List.of(eventEmitter.getContractAddress()),
Collections.emptyList(),
null);
final String filterId =
groupCreatingPrivacyNode.execute(
privacyTransactions.newFilter(privacyGroupId, filterParameter));
final CallPrivateSmartContractFunction storeTransaction =
privateContractTransactions.callSmartContractWithPrivacyGroupId(
eventEmitter.getContractAddress(),
eventEmitter.store(BigInteger.valueOf(VALUE_SET)).encodeFunctionCall(),
groupCreatingPrivacyNode.getTransactionSigningKey(),
POW_CHAIN_ID,
groupCreatingTenant,
privacyGroupId);
final String storeTransactionHash = groupCreatingPrivacyNode.execute(storeTransaction);
groupCreatingPrivacyNode.execute(
privacyTransactions.getPrivateTransactionReceipt(storeTransactionHash));
// check that getting the filter changes works for a member
groupCreatingPrivacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
multiTenancyPrivacyNode.getTokenForTenant(tenantToBeRemoved));
assertThat(
groupCreatingPrivacyNode.execute(
privacyTransactions.getFilterChanges(privacyGroupId, filterId)))
.hasSize(1);
groupCreatingPrivacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
multiTenancyPrivacyNode.getTokenForTenant(groupCreatingTenant));
final CallPrivateSmartContractFunction store2Transaction =
privateContractTransactions.callSmartContractWithPrivacyGroupId(
eventEmitter.getContractAddress(),
eventEmitter.store(BigInteger.valueOf(VALUE_SET)).encodeFunctionCall(),
groupCreatingPrivacyNode.getTransactionSigningKey(),
POW_CHAIN_ID,
groupCreatingTenant,
privacyGroupId);
final String store2TransactionHash = groupCreatingPrivacyNode.execute(store2Transaction);
groupCreatingPrivacyNode.execute(
privacyTransactions.getPrivateTransactionReceipt(store2TransactionHash));
// now remove from privacy group
final String removeTransactionHash =
removeFromPrivacyGroup(
privacyGroupId,
groupCreatingPrivacyNode,
groupCreatingTenant,
Credentials.create(groupCreatingPrivacyNode.getTransactionSigningKey()),
tenantToBeRemoved);
groupCreatingPrivacyNode.execute(
privacyTransactions.getPrivateTransactionReceipt(removeTransactionHash));
// check that it does not work anymore when member has been removed
groupCreatingPrivacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
multiTenancyPrivacyNode.getTokenForTenant(tenantToBeRemoved));
assertThatThrownBy(
() ->
groupCreatingPrivacyNode.execute(
privacyTransactions.getFilterChanges(privacyGroupId, filterId)))
.hasMessageContaining("Unauthorized");
}
private String createOnChainPrivacyGroup(final MultiTenancyPrivacyGroup group) {
final List<MultiTenancyPrivacyNode> multiTenancyPrivacyNodes = group.getPrivacyNodes();
final MultiTenancyPrivacyNode groupCreatorMultiTenancyPrivacyNode =
multiTenancyPrivacyNodes.get(0);
final PrivacyNode groupCreatorNode = group.getGroupCreatingPrivacyNode();
final String groupCreatorTenant = group.getGroupCreatingTenant();
final List<String> members = group.getTenants();
final String token = groupCreatorMultiTenancyPrivacyNode.getTokenForTenant(groupCreatorTenant);
final CreateOnChainPrivacyGroupTransaction createTx =
privacyTransactions.createOnChainPrivacyGroup(
groupCreatorNode, groupCreatorTenant, members, token);
final PrivacyRequestFactory.PrivxCreatePrivacyGroupResponse createResponse =
groupCreatorNode.execute(createTx);
final String privacyGroupId = createResponse.getPrivacyGroupId();
final List<Base64String> base64StringList =
members.stream().map(Base64String::wrap).collect(Collectors.toList());
for (final MultiTenancyPrivacyNode mtpn : multiTenancyPrivacyNodes) {
final PrivacyNode privacyNode = mtpn.getPrivacyNode();
for (final String tenant : mtpn.getTenants()) {
if (members.contains(tenant)) {
privacyNode
.getBesu()
.useAuthenticationTokenInHeaderForJsonRpc(mtpn.getTokenForTenant(tenant));
privacyNode.verify(onChainPrivacyGroupExists(privacyGroupId, base64StringList));
}
}
}
groupCreatorNode.getBesu().useAuthenticationTokenInHeaderForJsonRpc(token);
final String commitmentHash =
callGetParticipantsMethodAndReturnCommitmentHash(
privacyGroupId, groupCreatorNode, groupCreatorTenant);
final PrivateTransactionReceipt expectedReceipt =
buildExpectedAddMemberTransactionReceipt(
privacyGroupId, groupCreatorNode, groupCreatorTenant, members.toArray(new String[] {}));
for (final MultiTenancyPrivacyNode mtpn : multiTenancyPrivacyNodes) {
final PrivacyNode privacyNode = mtpn.getPrivacyNode();
for (final String tenant : mtpn.getTenants()) {
if (members.contains(tenant)) {
privacyNode
.getBesu()
.useAuthenticationTokenInHeaderForJsonRpc(mtpn.getTokenForTenant(tenant));
privacyNode.verify(
privateTransactionVerifier.validPrivateTransactionReceipt(
commitmentHash, expectedReceipt));
}
}
}
return privacyGroupId;
}
private String removeFromPrivacyGroup(
final String privacyGroupId,
final PrivacyNode node,
final String nodeRemovingMember,
final Credentials signer,
final String memberBeingRemoved) {
return node.execute(
privacyTransactions.removeFromPrivacyGroup(
privacyGroupId, nodeRemovingMember, signer, memberBeingRemoved));
}
}

@ -16,17 +16,11 @@ package org.hyperledger.besu.tests.web3j.privacy;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.hyperledger.besu.ethereum.privacy.group.OnChainGroupManagement.GET_PARTICIPANTS_METHOD_SIGNATURE;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.tests.acceptance.dsl.condition.eth.EthConditions;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyAcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.condition.ExpectValidOnChainPrivacyGroupCreated;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.transaction.CreateOnChainPrivacyGroupTransaction;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.miner.MinerTransactions;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.PrivacyRequestFactory.PrivxCreatePrivacyGroupResponse;
import org.hyperledger.besu.tests.web3j.generated.EventEmitter;
import java.math.BigInteger;
@ -36,7 +30,6 @@ import java.util.List;
import java.util.Optional;
import com.google.common.collect.Lists;
import org.apache.tuweni.bytes.Bytes;
import org.junit.Before;
import org.junit.Test;
import org.web3j.crypto.Credentials;
@ -45,11 +38,10 @@ import org.web3j.protocol.core.methods.response.EthCall;
import org.web3j.protocol.core.methods.response.Log;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.tx.Contract;
import org.web3j.utils.Base64String;
public class OnChainPrivacyAcceptanceTest extends PrivacyAcceptanceTestBase {
public class OnChainPrivacyAcceptanceTest extends OnChainPrivacyAcceptanceTestBase {
private static final long POW_CHAIN_ID = 2018;
protected static final long POW_CHAIN_ID = 2018;
private PrivacyNode alice;
private PrivacyNode bob;
@ -67,13 +59,13 @@ public class OnChainPrivacyAcceptanceTest extends PrivacyAcceptanceTestBase {
public void setUp() throws Exception {
alice =
privacyBesu.createOnChainPrivacyGroupEnabledMinerNode(
"node1", privacyAccountResolver.resolve(0), Address.PRIVACY);
"node1", privacyAccountResolver.resolve(0), Address.PRIVACY, false);
bob =
privacyBesu.createOnChainPrivacyGroupEnabledNode(
"node2", privacyAccountResolver.resolve(1), Address.PRIVACY);
"node2", privacyAccountResolver.resolve(1), Address.PRIVACY, false);
charlie =
privacyBesu.createOnChainPrivacyGroupEnabledNode(
"node3", privacyAccountResolver.resolve(2), Address.PRIVACY);
"node3", privacyAccountResolver.resolve(2), Address.PRIVACY, false);
privacyCluster.start(alice, bob, charlie);
}
@ -463,43 +455,6 @@ public class OnChainPrivacyAcceptanceTest extends PrivacyAcceptanceTestBase {
return contract;
}
/**
* Crete an onchain privacy group. The privacy group id will be randomly generated.
*
* <p>This method also checks that each node member has successfully processed the transaction and
* has the expected list of member for the group.
*
* @param members the list of members of the privacy group. The first member of the list will be
* the creator of the group.
* @return the id of the privacy group
*/
private String createOnChainPrivacyGroup(final PrivacyNode... members) {
final PrivacyNode groupCreator = members[0];
final CreateOnChainPrivacyGroupTransaction createTx =
privacyTransactions.createOnChainPrivacyGroup(groupCreator, members);
final PrivxCreatePrivacyGroupResponse createResponse = groupCreator.execute(createTx);
final String privacyGroupId = createResponse.getPrivacyGroupId();
for (final PrivacyNode member : members) {
member.verify(onChainPrivacyGroupExists(privacyGroupId, members));
}
final String commitmentHash = calculateAddParticipantPMTHash(privacyGroupId, groupCreator);
final PrivateTransactionReceipt expectedReceipt =
buildExpectedAddMemberTransactionReceipt(privacyGroupId, groupCreator, members);
for (final PrivacyNode member : members) {
member.verify(
privateTransactionVerifier.validPrivateTransactionReceipt(
commitmentHash, expectedReceipt));
}
return privacyGroupId;
}
private String addMembersToPrivacyGroup(
final String privacyGroupId,
final PrivacyNode nodeAddingMember,
@ -517,71 +472,15 @@ public class OnChainPrivacyAcceptanceTest extends PrivacyAcceptanceTestBase {
final PrivacyNode memberBeingRemoved) {
return nodeRemovingMember.execute(
privacyTransactions.removeFromPrivacyGroup(
privacyGroupId, nodeRemovingMember, signer, memberBeingRemoved));
}
private String calculateAddParticipantPMTHash(
final String privacyGroupId, final PrivacyNode groupCreator) {
return groupCreator.execute(
privateContractTransactions.callOnChainPermissioningSmartContract(
Address.ONCHAIN_PRIVACY_PROXY.toHexString(),
GET_PARTICIPANTS_METHOD_SIGNATURE
+ Bytes.fromBase64String(groupCreator.getEnclaveKey()).toUnprefixedHexString(),
groupCreator.getTransactionSigningKey(),
POW_CHAIN_ID,
groupCreator.getEnclaveKey(),
privacyGroupId));
}
private PrivateTransactionReceipt buildExpectedAddMemberTransactionReceipt(
final String privacyGroupId, final PrivacyNode groupCreator, final PrivacyNode[] members) {
final StringBuilder output = new StringBuilder();
// hex prefix
output.append("0x");
// Dynamic array offset
output.append("0000000000000000000000000000000000000000000000000000000000000020");
// Length of the array (with padded zeros to the left)
output.append(Quantity.longToPaddedHex(members.length, 32).substring(2));
// Each member enclave key converted from Base64 to bytes
for (final PrivacyNode member : members) {
output.append(Bytes.fromBase64String(member.getEnclaveKey()).toUnprefixedHexString());
}
return new PrivateTransactionReceipt(
null,
groupCreator.getAddress().toHexString(),
Address.ONCHAIN_PRIVACY_PROXY.toHexString(),
output.toString(),
Collections.emptyList(),
null,
null,
groupCreator.getEnclaveKey(),
null,
privacyGroupId,
"0x1",
null);
}
/**
* This method will check if a privacy group with the specified id and list of members exists.
* Each one of the members node will be queried to ensure that they all have the same privacy
* group in their private state.
*
* @param privacyGroupId the id of the privacy group
* @param members the list of member in the privacy group
*/
private void checkOnChainPrivacyGroupExists(
final String privacyGroupId, final PrivacyNode... members) {
for (final PrivacyNode member : members) {
member.verify(onChainPrivacyGroupExists(privacyGroupId, members));
}
privacyGroupId,
nodeRemovingMember.getEnclaveKey(),
signer,
memberBeingRemoved.getEnclaveKey()));
}
/**
* This method will send a transaction to lock the privacy group identified by the specified id.
* This also checks if the lock transaction was successful (see {@link
* org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.PrivacyRequestFactory#privxLockPrivacyGroup(PrivacyNode,
* Base64String)}
* This also checks if the lock transaction was successful.
*
* @return the hash of the lock privacy group transaction
*/
@ -590,17 +489,4 @@ public class OnChainPrivacyAcceptanceTest extends PrivacyAcceptanceTestBase {
return member.execute(
privacyTransactions.privxLockPrivacyGroupAndCheck(privacyGroupId, member, signer));
}
private ExpectValidOnChainPrivacyGroupCreated onChainPrivacyGroupExists(
final String privacyGroupId, final PrivacyNode... members) {
return privateTransactionVerifier.onChainPrivacyGroupExists(privacyGroupId, members);
}
private String getContractDeploymentCommitmentHash(final Contract contract) {
final Optional<TransactionReceipt> transactionReceipt = contract.getTransactionReceipt();
assertThat(transactionReceipt).isPresent();
final PrivateTransactionReceipt privateTransactionReceipt =
(PrivateTransactionReceipt) transactionReceipt.get();
return privateTransactionReceipt.getcommitmentHash();
}
}

@ -0,0 +1,177 @@
/*
* Copyright 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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.tests.web3j.privacy;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.privacy.group.OnChainGroupManagement.GET_PARTICIPANTS_METHOD_SIGNATURE;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyAcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.condition.ExpectValidOnChainPrivacyGroupCreated;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.transaction.CreateOnChainPrivacyGroupTransaction;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.PrivacyRequestFactory;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.tuweni.bytes.Bytes;
import org.web3j.protocol.besu.response.privacy.PrivateTransactionReceipt;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.tx.Contract;
import org.web3j.utils.Base64String;
public class OnChainPrivacyAcceptanceTestBase extends PrivacyAcceptanceTestBase {
protected String createOnChainPrivacyGroup(final PrivacyNode... members) {
final List<String> addresses =
Arrays.asList(members).stream().map(m -> m.getEnclaveKey()).collect(Collectors.toList());
return createOnChainPrivacyGroup(members[0].getEnclaveKey(), addresses, members);
}
/**
* Crete an onchain privacy group. The privacy group id will be randomly generated.
*
* <p>This method also checks that each node member has successfully processed the transaction and
* has the expected list of member for the group.
*
* @param members the list of members of the privacy group. The first member of the list will be
* the creator of the group.
* @return the id of the privacy group
*/
protected String createOnChainPrivacyGroup(
final String privateFrom, final List<String> addresses, final PrivacyNode... members) {
final PrivacyNode groupCreator = members[0];
final CreateOnChainPrivacyGroupTransaction createTx =
privacyTransactions.createOnChainPrivacyGroup(groupCreator, privateFrom, addresses);
final PrivacyRequestFactory.PrivxCreatePrivacyGroupResponse createResponse =
groupCreator.execute(createTx);
final String privacyGroupId = createResponse.getPrivacyGroupId();
final List<Base64String> membersEnclaveKeys =
Arrays.stream(members)
.map(m -> Base64String.wrap(m.getEnclaveKey()))
.collect(Collectors.toList());
for (final PrivacyNode member : members) {
member.verify(onChainPrivacyGroupExists(privacyGroupId, membersEnclaveKeys));
}
final String commitmentHash =
callGetParticipantsMethodAndReturnCommitmentHash(privacyGroupId, groupCreator, privateFrom);
final PrivateTransactionReceipt expectedReceipt =
buildExpectedAddMemberTransactionReceipt(
privacyGroupId, groupCreator, addresses.toArray(new String[] {}));
for (final PrivacyNode member : members) {
member.verify(
privateTransactionVerifier.validPrivateTransactionReceipt(
commitmentHash, expectedReceipt));
}
return privacyGroupId;
}
protected String callGetParticipantsMethodAndReturnCommitmentHash(
final String privacyGroupId, final PrivacyNode groupCreator, final String privateFrom) {
return groupCreator.execute(
privateContractTransactions.callOnChainPermissioningSmartContract(
Address.ONCHAIN_PRIVACY_PROXY.toHexString(),
GET_PARTICIPANTS_METHOD_SIGNATURE.toString(),
groupCreator.getTransactionSigningKey(),
POW_CHAIN_ID,
privateFrom,
privacyGroupId));
}
protected PrivateTransactionReceipt buildExpectedAddMemberTransactionReceipt(
final String privacyGroupId, final PrivacyNode groupCreator, final String[] members) {
return buildExpectedAddMemberTransactionReceipt(
privacyGroupId, groupCreator, groupCreator.getEnclaveKey(), members);
}
protected PrivateTransactionReceipt buildExpectedAddMemberTransactionReceipt(
final String privacyGroupId,
final PrivacyNode groupCreator,
final String privateFrom,
final String[] members) {
final StringBuilder output = new StringBuilder();
// hex prefix
output.append("0x");
// Dynamic array offset
output.append("0000000000000000000000000000000000000000000000000000000000000020");
// Length of the array (with padded zeros to the left)
output.append(Quantity.longToPaddedHex(members.length, 32).substring(2));
// Each member enclave key converted from Base64 to bytes
for (final String member : members) {
output.append(Bytes.fromBase64String(member).toUnprefixedHexString());
}
return new PrivateTransactionReceipt(
null,
groupCreator.getAddress().toHexString(),
Address.ONCHAIN_PRIVACY_PROXY.toHexString(),
output.toString(),
Collections.emptyList(),
null,
null,
privateFrom,
null,
privacyGroupId,
"0x1",
null);
}
protected ExpectValidOnChainPrivacyGroupCreated onChainPrivacyGroupExists(
final String privacyGroupId, final List<Base64String> members) {
return privateTransactionVerifier.onChainPrivacyGroupExists(privacyGroupId, members);
}
protected String getContractDeploymentCommitmentHash(final Contract contract) {
final Optional<TransactionReceipt> transactionReceipt = contract.getTransactionReceipt();
assertThat(transactionReceipt).isPresent();
final PrivateTransactionReceipt privateTransactionReceipt =
(PrivateTransactionReceipt) transactionReceipt.get();
return privateTransactionReceipt.getcommitmentHash();
}
/**
* This method will check if a privacy group with the specified id and list of members exists.
* Each one of the members node will be queried to ensure that they all have the same privacy
* group in their private state.
*
* @param privacyGroupId the id of the privacy group
* @param members the list of member in the privacy group
*/
protected void checkOnChainPrivacyGroupExists(
final String privacyGroupId, final PrivacyNode... members) {
final List<Base64String> membersEnclaveKeys =
Arrays.stream(members)
.map(PrivacyNode::getEnclaveKey)
.map(Base64String::wrap)
.collect(Collectors.toList());
for (final PrivacyNode member : members) {
member.verify(onChainPrivacyGroupExists(privacyGroupId, membersEnclaveKeys));
}
}
}

@ -3,6 +3,16 @@ password = "$2a$10$l3GA7K8g6rJ/Yv.YFSygCuI9byngpEzxgWS9qEg5emYDZomQW7fGC"
permissions = ["fakePermission", "*:*"]
privacyPublicKey = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="
[Users.user2]
password = "$2a$10$0ikMUcSYugKmnXilimhc1eGNnfMRvKt2PxQJPo1oCemN16QL2NNo."
permissions = ["fakePermission", "*:*"]
privacyPublicKey = "Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs="
[Users.user3]
password = "$2a$10$Mydyzpul6CtgPRbUd6It2OpZDOfqOocpi6.UYhlyU5aphQHi1iQZq"
permissions = ["fakePermission", "*:*"]
privacyPublicKey = "k2zXEin4Ip/qBGlRkJejnGWdP9cjkK+DAvKNW31L2C8="
[Users.failUser]
password = "$2a$10$l3GA7K8g6rJ/Yv.YFSygCuI9byngpEzxgWS9qEg5emYDZomQW7fGC"
permissions = ["fakePermission", "*:*"]

@ -860,6 +860,7 @@ public class RunnerBuilder {
privateWebSocketMethodsFactory.methods().forEach(websocketMethodsFactory::addMethods);
}
final WebSocketRequestHandler websocketRequestHandler =
new WebSocketRequestHandler(
vertx,

@ -1842,12 +1842,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
privacyParametersBuilder.setMultiTenancyEnabled(isPrivacyMultiTenancyEnabled);
privacyParametersBuilder.setOnchainPrivacyGroupsEnabled(isOnchainPrivacyGroupEnabled);
if (isPrivacyMultiTenancyEnabled && isOnchainPrivacyGroupEnabled) {
throw new ParameterException(
commandLine,
"Privacy multi-tenancy and onchain privacy groups cannot be used together");
}
final boolean hasPrivacyPublicKey = privacyPublicKeyFile != null;
if (hasPrivacyPublicKey && !isPrivacyMultiTenancyEnabled) {
try {

@ -3129,20 +3129,6 @@ public class BesuCommandTest extends CommandTestAbstract {
assertThat(privacyParameters.isOnchainPrivacyGroupsEnabled()).isEqualTo(true);
}
@Test
public void onchainPrivacyAndMultiTenancyCannotBeUsedTogether() {
parseCommand(
"--privacy-enabled",
"--privacy-onchain-groups-enabled",
"--privacy-multi-tenancy-enabled",
"--rpc-http-authentication-jwt-public-key-file",
"/non/existent/file",
"--rpc-http-authentication-enabled");
assertThat(commandErrorOutput.toString())
.startsWith("Privacy multi-tenancy and onchain privacy groups cannot be used together");
}
@Test
public void privacyMarkerTransactionSigningKeyFileRequiredIfMinGasPriceNonZero() {
parseCommand("--privacy-enabled", "--privacy-public-key-file", ENCLAVE_PUBLIC_KEY_PATH);

@ -38,6 +38,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcRespon
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcUnauthorizedResponse;
import org.hyperledger.besu.ethereum.api.tls.TlsClientAuthConfiguration;
import org.hyperledger.besu.ethereum.api.tls.TlsConfiguration;
import org.hyperledger.besu.ethereum.privacy.MultiTenancyValidationException;
import org.hyperledger.besu.metrics.BesuMetricCategory;
import org.hyperledger.besu.nat.NatMethod;
import org.hyperledger.besu.nat.NatService;
@ -604,6 +605,8 @@ public class JsonRpcHttpService {
} catch (final InvalidJsonRpcParameters e) {
LOG.debug("Invalid Params", e);
return errorResponse(id, JsonRpcError.INVALID_PARAMS);
} catch (final MultiTenancyValidationException e) {
return unauthorizedResponse(id, JsonRpcError.UNAUTHORIZED);
} catch (final RuntimeException e) {
LOG.error("Error processing JSON-RPC requestBody", e);
return errorResponse(id, JsonRpcError.INTERNAL_ERROR);

@ -20,32 +20,32 @@ import java.util.List;
public class OrionConfiguration {
private final Path publicKey;
private final Path privateKey;
private final Path[] publicKeys;
private final Path[] privateKeys;
private final Path tempDir;
private final List<String> otherNodes = new ArrayList<>();
private final boolean clearKnownNodes;
public OrionConfiguration(
final Path publicKey,
final Path privateKey,
final Path[] publicKeys,
final Path[] privateKeys,
final Path tempDir,
final List<String> otherNodes,
final boolean clearKnownNodes) {
this.publicKey = publicKey;
this.privateKey = privateKey;
this.publicKeys = publicKeys;
this.privateKeys = privateKeys;
this.tempDir = tempDir;
this.otherNodes.addAll(otherNodes);
this.clearKnownNodes = clearKnownNodes;
}
public Path getPublicKey() {
return publicKey;
public Path[] getPublicKeys() {
return publicKeys;
}
public Path getPrivateKey() {
return privateKey;
public Path[] getPrivateKeys() {
return privateKeys;
}
public Path getTempDir() {

@ -15,19 +15,24 @@
package org.hyperledger.orion.testutil;
public class OrionKeyConfiguration {
private final String pubKeyPath;
private final String privKeyPath;
private final String[] pubKeyPaths;
private final String[] privKeyPaths;
public OrionKeyConfiguration(final String pubKeyPath, final String privKeyPath) {
this.pubKeyPath = pubKeyPath;
this.privKeyPath = privKeyPath;
this.pubKeyPaths = new String[] {pubKeyPath};
this.privKeyPaths = new String[] {privKeyPath};
}
public String getPubKeyPath() {
return pubKeyPath;
public OrionKeyConfiguration(final String[] pubKeyPaths, final String[] privKeyPaths) {
this.pubKeyPaths = pubKeyPaths;
this.privKeyPaths = privKeyPaths;
}
public String getPrivKeyPath() {
return privKeyPath;
public String[] getPubKeyPaths() {
return pubKeyPaths;
}
public String[] getPrivKeyPaths() {
return privKeyPaths;
}
}

@ -96,21 +96,21 @@ public class OrionTestHarness {
private static String readFile(final Path path) {
try {
return readLines(path.toFile(), Charsets.UTF_8).get(0);
} catch (IOException e) {
} catch (final IOException e) {
e.printStackTrace();
return "";
}
}
public URI clientUrl() {
HttpUrl httpUrl =
final HttpUrl httpUrl =
new HttpUrl.Builder().scheme("http").host(HOST).port(orion.clientPort()).build();
return URI.create(httpUrl.toString());
}
public URI nodeUrl() {
HttpUrl httpUrl =
final HttpUrl httpUrl =
new HttpUrl.Builder().scheme("http").host(HOST).port(orion.nodePort()).build();
return URI.create(httpUrl.toString());
@ -136,10 +136,10 @@ public class OrionTestHarness {
+ "\"\n"
+ "storage = \"leveldb:database/orion_node\"\n"
+ "publickeys = ["
+ joinPathsAsTomlListEntry(orionConfiguration.getPublicKey())
+ joinPathsAsTomlListEntry(orionConfiguration.getPublicKeys())
+ "]\n"
+ "privatekeys = ["
+ joinPathsAsTomlListEntry(orionConfiguration.getPrivateKey())
+ joinPathsAsTomlListEntry(orionConfiguration.getPrivateKeys())
+ "]\n"
+ "workdir= \""
+ orionConfiguration.getTempDir().toString()
@ -160,9 +160,9 @@ public class OrionTestHarness {
}
private static String joinStringsAsTomlListEntry(final List<String> strings) {
StringBuilder builder = new StringBuilder();
final StringBuilder builder = new StringBuilder();
boolean first = true;
for (String string : strings) {
for (final String string : strings) {
if (!first) {
builder.append(",");
}

@ -18,36 +18,59 @@ import static org.apache.tuweni.io.file.Files.copyResource;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class OrionTestHarnessFactory {
public static OrionTestHarness create(final Path tempDir, final OrionKeyConfiguration orionConfig)
throws IOException {
public static OrionTestHarness create(
final Path tempDir, final OrionKeyConfiguration orionConfig) {
return create(
tempDir,
orionConfig.getPubKeyPath(),
orionConfig.getPrivKeyPath(),
orionConfig.getPubKeyPaths(),
orionConfig.getPrivKeyPaths(),
Collections.emptyList());
}
public static OrionTestHarness create(
final Path tempDir,
final String pubKeyPath,
final String privKeyPath,
final List<String> othernodes)
throws IOException {
final Path key1pub = copyResource(pubKeyPath, tempDir.resolve(pubKeyPath));
final Path key1key = copyResource(privKeyPath, tempDir.resolve(privKeyPath));
return create(tempDir, key1pub, key1key, othernodes);
final String[] pubKeyPaths,
final String[] privKeyPaths,
final List<String> othernodes) {
final Path[] pubKeys =
Arrays.stream(pubKeyPaths)
.map(
(pk) -> {
try {
return copyResource(pk, tempDir.resolve(pk));
} catch (final IOException e) {
throw new RuntimeException(e);
}
})
.toArray(Path[]::new);
final Path[] privKeys =
Arrays.stream(privKeyPaths)
.map(
(pk) -> {
try {
return copyResource(pk, tempDir.resolve(pk));
} catch (final IOException e) {
throw new RuntimeException(e);
}
})
.toArray(Path[]::new);
return create(tempDir, pubKeys, privKeys, othernodes);
}
public static OrionTestHarness create(
final Path tempDir, final Path key1pub, final Path key1key, final List<String> othernodes) {
final Path tempDir,
final Path[] key1pubs,
final Path[] key1keys,
final List<String> othernodes) {
return new OrionTestHarness(
new OrionConfiguration(key1pub, key1key, tempDir, othernodes, false));
new OrionConfiguration(key1pubs, key1keys, tempDir, othernodes, false));
}
}

Loading…
Cancel
Save