diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivGetPrivateTransactionIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivGetPrivateTransactionIntegrationTest.java index 0293c702af4..ee54531158b 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivGetPrivateTransactionIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivGetPrivateTransactionIntegrationTest.java @@ -26,6 +26,7 @@ import org.hyperledger.besu.enclave.types.SendResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivGetPrivateTransaction; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.PrivateTransactionLegacyResult; @@ -76,6 +77,8 @@ public class PrivGetPrivateTransactionIntegrationTest { private static Vertx vertx = Vertx.vertx(); + private EnclavePublicKeyProvider enclavePublicKeyProvider = (user) -> ENCLAVE_PUBLIC_KEY; + @BeforeClass public static void setUpOnce() throws Exception { folder.create(); @@ -89,7 +92,7 @@ public static void setUpOnce() throws Exception { final EnclaveFactory factory = new EnclaveFactory(vertx); enclave = factory.createVertxEnclave(testHarness.clientUrl()); - privacyController = new PrivacyController(enclave, ENCLAVE_PUBLIC_KEY, null, null, null, null); + privacyController = new PrivacyController(enclave, null, null, null, null); } @AfterClass @@ -148,7 +151,7 @@ public void before() { public void returnsStoredPrivateTransaction() { final PrivGetPrivateTransaction privGetPrivateTransaction = - new PrivGetPrivateTransaction(blockchain, privacyController); + new PrivGetPrivateTransaction(blockchain, privacyController, enclavePublicKeyProvider); when(blockchain.transactionByHash(any(Hash.class))) .thenReturn(Optional.of(returnedTransaction)); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/EnclavePublicKeyProvider.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/EnclavePublicKeyProvider.java new file mode 100644 index 00000000000..44a3350530b --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/EnclavePublicKeyProvider.java @@ -0,0 +1,24 @@ +/* + * 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.ethereum.api.jsonrpc.internal.privacy.methods; + +import java.util.Optional; + +import io.vertx.ext.auth.User; + +@FunctionalInterface +public interface EnclavePublicKeyProvider { + String getEnclaveKey(Optional user); +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/PrivacySendTransaction.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/PrivacySendTransaction.java index aa1cfc24060..8750a1f3497 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/PrivacySendTransaction.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/PrivacySendTransaction.java @@ -37,9 +37,13 @@ public class PrivacySendTransaction { private static final Logger LOG = LogManager.getLogger(); protected final PrivacyController privacyController; + private EnclavePublicKeyProvider enclavePublicKeyProvider; - public PrivacySendTransaction(final PrivacyController privacyController) { + public PrivacySendTransaction( + final PrivacyController privacyController, + final EnclavePublicKeyProvider enclavePublicKeyProvider) { this.privacyController = privacyController; + this.enclavePublicKeyProvider = enclavePublicKeyProvider; } public PrivateTransaction validateAndDecodeRequest(final JsonRpcRequestContext request) @@ -74,7 +78,10 @@ public JsonRpcResponse validateAndExecute( final String privacyGroupId, final Supplier successfulJsonRpcResponse) { return privacyController - .validatePrivateTransaction(privateTransaction, privacyGroupId) + .validatePrivateTransaction( + privateTransaction, + privacyGroupId, + enclavePublicKeyProvider.getEnclaveKey(request.getUser())) .either( successfulJsonRpcResponse, (errorReason) -> diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransaction.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransaction.java index 85d8a698464..918b1d2c529 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransaction.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransaction.java @@ -19,6 +19,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacySendTransaction; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacySendTransaction.ErrorResponseException; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; @@ -33,14 +34,19 @@ public class EeaSendRawTransaction implements JsonRpcMethod { private final PrivacySendTransaction privacySendTransaction; + private EnclavePublicKeyProvider enclavePublicKeyProvider; private TransactionPool transactionPool; private PrivacyController privacyController; public EeaSendRawTransaction( - final TransactionPool transactionPool, final PrivacyController privacyController) { + final TransactionPool transactionPool, + final PrivacyController privacyController, + final EnclavePublicKeyProvider enclavePublicKeyProvider) { this.transactionPool = transactionPool; this.privacyController = privacyController; - this.privacySendTransaction = new PrivacySendTransaction(privacyController); + this.privacySendTransaction = + new PrivacySendTransaction(privacyController, enclavePublicKeyProvider); + this.enclavePublicKeyProvider = enclavePublicKeyProvider; } @Override @@ -59,7 +65,9 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { final SendTransactionResponse sendTransactionResponse; try { - sendTransactionResponse = privacyController.sendTransaction(privateTransaction); + sendTransactionResponse = + privacyController.sendTransaction( + privateTransaction, enclavePublicKeyProvider.getEnclaveKey(requestContext.getUser())); } catch (final Exception e) { return new JsonRpcErrorResponse( requestContext.getRequest().getId(), diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCreatePrivacyGroup.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCreatePrivacyGroup.java index dce56fc558e..23e92412160 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCreatePrivacyGroup.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCreatePrivacyGroup.java @@ -21,6 +21,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.parameters.CreatePrivacyGroupParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; @@ -33,9 +34,13 @@ public class PrivCreatePrivacyGroup implements JsonRpcMethod { private static final Logger LOG = getLogger(); private PrivacyController privacyController; + private EnclavePublicKeyProvider enclavePublicKeyProvider; - public PrivCreatePrivacyGroup(final PrivacyController privacyController) { + public PrivCreatePrivacyGroup( + final PrivacyController privacyController, + final EnclavePublicKeyProvider enclavePublicKeyProvider) { this.privacyController = privacyController; + this.enclavePublicKeyProvider = enclavePublicKeyProvider; } @Override @@ -59,7 +64,10 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { try { response = privacyController.createPrivacyGroup( - parameter.getAddresses(), parameter.getName(), parameter.getDescription()); + parameter.getAddresses(), + parameter.getName(), + parameter.getDescription(), + enclavePublicKeyProvider.getEnclaveKey(requestContext.getUser())); } catch (Exception e) { LOG.error("Failed to create privacy group", e); return new JsonRpcErrorResponse( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDeletePrivacyGroup.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDeletePrivacyGroup.java index 7f98a8c70c1..c5cc9eb311d 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDeletePrivacyGroup.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDeletePrivacyGroup.java @@ -19,7 +19,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.privacy.PrivacyController; @@ -30,9 +32,13 @@ public class PrivDeletePrivacyGroup implements JsonRpcMethod { private static final Logger LOG = getLogger(); private PrivacyController privacyController; + private EnclavePublicKeyProvider enclavePublicKeyProvider; - public PrivDeletePrivacyGroup(final PrivacyController privacyController) { + public PrivDeletePrivacyGroup( + final PrivacyController privacyController, + final EnclavePublicKeyProvider enclavePublicKeyProvider) { this.privacyController = privacyController; + this.enclavePublicKeyProvider = enclavePublicKeyProvider; } @Override @@ -48,10 +54,12 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { final String response; try { - response = privacyController.deletePrivacyGroup(privacyGroupId); + response = + privacyController.deletePrivacyGroup( + privacyGroupId, enclavePublicKeyProvider.getEnclaveKey(requestContext.getUser())); } catch (Exception e) { LOG.error("Failed to fetch transaction", e); - return new JsonRpcSuccessResponse( + return new JsonRpcErrorResponse( requestContext.getRequest().getId(), JsonRpcError.DELETE_PRIVACY_GROUP_ERROR); } return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), response); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransaction.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransaction.java index c49c823ba4b..68fd2889472 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransaction.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransaction.java @@ -18,6 +18,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacySendTransaction; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacySendTransaction.ErrorResponseException; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; @@ -35,10 +36,15 @@ public class PrivDistributeRawTransaction implements JsonRpcMethod { private final PrivacyController privacyController; private final PrivacySendTransaction privacySendTransaction; + private EnclavePublicKeyProvider enclavePublicKeyProvider; - public PrivDistributeRawTransaction(final PrivacyController privacyController) { + public PrivDistributeRawTransaction( + final PrivacyController privacyController, + final EnclavePublicKeyProvider enclavePublicKeyProvider) { this.privacyController = privacyController; - this.privacySendTransaction = new PrivacySendTransaction(privacyController); + this.privacySendTransaction = + new PrivacySendTransaction(privacyController, enclavePublicKeyProvider); + this.enclavePublicKeyProvider = enclavePublicKeyProvider; } @Override @@ -57,7 +63,9 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { final SendTransactionResponse sendTransactionResponse; try { - sendTransactionResponse = privacyController.sendTransaction(privateTransaction); + sendTransactionResponse = + privacyController.sendTransaction( + privateTransaction, enclavePublicKeyProvider.getEnclaveKey(requestContext.getUser())); } catch (final Exception e) { return new JsonRpcErrorResponse( requestContext.getRequest().getId(), diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivFindPrivacyGroup.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivFindPrivacyGroup.java index 4b0900a6982..16df647db85 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivFindPrivacyGroup.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivFindPrivacyGroup.java @@ -20,6 +20,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; @@ -34,9 +35,13 @@ public class PrivFindPrivacyGroup implements JsonRpcMethod { private static final Logger LOG = getLogger(); private PrivacyController privacyController; + private EnclavePublicKeyProvider enclavePublicKeyProvider; - public PrivFindPrivacyGroup(final PrivacyController privacyController) { + public PrivFindPrivacyGroup( + final PrivacyController privacyController, + final EnclavePublicKeyProvider enclavePublicKeyProvider) { this.privacyController = privacyController; + this.enclavePublicKeyProvider = enclavePublicKeyProvider; } @Override @@ -54,7 +59,10 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { PrivacyGroup[] response; try { - response = privacyController.findPrivacyGroup(Arrays.asList(addresses)); + response = + privacyController.findPrivacyGroup( + Arrays.asList(addresses), + enclavePublicKeyProvider.getEnclaveKey(requestContext.getUser())); } catch (Exception e) { LOG.error("Failed to fetch privacy group", e); return new JsonRpcErrorResponse( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetEeaTransactionCount.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetEeaTransactionCount.java index 358fa666e1d..dbdc8d55a34 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetEeaTransactionCount.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetEeaTransactionCount.java @@ -19,6 +19,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; @@ -34,9 +35,13 @@ public class PrivGetEeaTransactionCount implements JsonRpcMethod { private static final Logger LOG = getLogger(); private PrivacyController privacyController; + private EnclavePublicKeyProvider enclavePublicKeyProvider; - public PrivGetEeaTransactionCount(final PrivacyController privacyController) { + public PrivGetEeaTransactionCount( + final PrivacyController privacyController, + final EnclavePublicKeyProvider enclavePublicKeyProvider) { this.privacyController = privacyController; + this.enclavePublicKeyProvider = enclavePublicKeyProvider; } @Override @@ -56,7 +61,12 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { final String[] privateFor = requestContext.getRequiredParameter(2, String[].class); try { - final long nonce = privacyController.determineNonce(privateFrom, privateFor, address); + final long nonce = + privacyController.determineNonce( + privateFrom, + privateFor, + address, + enclavePublicKeyProvider.getEnclaveKey(requestContext.getUser())); return new JsonRpcSuccessResponse( requestContext.getRequest().getId(), Quantity.create(nonce)); } catch (final Exception e) { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransaction.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransaction.java index b49faf126d6..f1c9e1f5df8 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransaction.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransaction.java @@ -21,6 +21,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.PrivateTransactionGroupResult; @@ -41,11 +42,15 @@ public class PrivGetPrivateTransaction implements JsonRpcMethod { private final BlockchainQueries blockchain; private final PrivacyController privacyController; + private EnclavePublicKeyProvider enclavePublicKeyProvider; public PrivGetPrivateTransaction( - final BlockchainQueries blockchain, final PrivacyController privacyController) { + final BlockchainQueries blockchain, + final PrivacyController privacyController, + final EnclavePublicKeyProvider enclavePublicKeyProvider) { this.blockchain = blockchain; this.privacyController = privacyController; + this.enclavePublicKeyProvider = enclavePublicKeyProvider; } @Override @@ -68,7 +73,8 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { LOG.trace("Fetching transaction information"); final ReceiveResponse receiveResponse = privacyController.retrieveTransaction( - resultTransaction.getTransaction().getPayload().toBase64String()); + resultTransaction.getTransaction().getPayload().toBase64String(), + enclavePublicKeyProvider.getEnclaveKey(requestContext.getUser())); LOG.trace("Received transaction information"); final BytesValueRLPInput input = diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionCount.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionCount.java index 34284f19276..dd7d750dc45 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionCount.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionCount.java @@ -17,6 +17,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; @@ -28,9 +29,13 @@ public class PrivGetTransactionCount implements JsonRpcMethod { private final PrivacyController privacyController; + private EnclavePublicKeyProvider enclavePublicKeyProvider; - public PrivGetTransactionCount(final PrivacyController privacyController) { + public PrivGetTransactionCount( + final PrivacyController privacyController, + final EnclavePublicKeyProvider enclavePublicKeyProvider) { this.privacyController = privacyController; + this.enclavePublicKeyProvider = enclavePublicKeyProvider; } @Override @@ -48,7 +53,11 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { final Address address = requestContext.getRequiredParameter(0, Address.class); final String privacyGroupId = requestContext.getRequiredParameter(1, String.class); - final long nonce = privacyController.determineNonce(address, privacyGroupId); + final long nonce = + privacyController.determineNonce( + address, + privacyGroupId, + enclavePublicKeyProvider.getEnclaveKey(requestContext.getUser())); return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), Quantity.create(nonce)); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceipt.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceipt.java index e3f2933aef8..d3dd65a100e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceipt.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceipt.java @@ -23,6 +23,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; @@ -56,14 +57,17 @@ public class PrivGetTransactionReceipt implements JsonRpcMethod { private final BlockchainQueries blockchain; private PrivacyParameters privacyParameters; private PrivacyController privacyController; + private EnclavePublicKeyProvider enclavePublicKeyProvider; public PrivGetTransactionReceipt( final BlockchainQueries blockchain, final PrivacyParameters privacyParameters, - final PrivacyController privacyController) { + final PrivacyController privacyController, + final EnclavePublicKeyProvider enclavePublicKeyProvider) { this.blockchain = blockchain; this.privacyParameters = privacyParameters; this.privacyController = privacyController; + this.enclavePublicKeyProvider = enclavePublicKeyProvider; } @Override @@ -92,7 +96,9 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { final String privacyGroupId; try { final ReceiveResponse receiveResponse = - privacyController.retrieveTransaction(transaction.getPayload().toBase64String()); + privacyController.retrieveTransaction( + transaction.getPayload().toBase64String(), + enclavePublicKeyProvider.getEnclaveKey(requestContext.getUser())); LOG.trace("Received transaction information"); final BytesValueRLPInput input = diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EeaJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EeaJsonRpcMethods.java index 842133ba203..71edf1d4698 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EeaJsonRpcMethods.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EeaJsonRpcMethods.java @@ -17,6 +17,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.eea.EeaSendRawTransaction; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivGetEeaTransactionCount; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; @@ -38,14 +39,17 @@ public EeaJsonRpcMethods( } @Override - protected RpcApi getApiGroup() { - return RpcApis.EEA; + protected Map create( + final PrivacyController privacyController, + final EnclavePublicKeyProvider enclavePublicKeyProvider) { + return mapOf( + new EeaSendRawTransaction( + getTransactionPool(), privacyController, enclavePublicKeyProvider), + new PrivGetEeaTransactionCount(privacyController, enclavePublicKeyProvider)); } @Override - protected Map create(final PrivacyController privacyController) { - return mapOf( - new EeaSendRawTransaction(getTransactionPool(), privacyController), - new PrivGetEeaTransactionCount(privacyController)); + protected RpcApi getApiGroup() { + return RpcApis.EEA; } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivJsonRpcMethods.java index 82744f594c9..4400dbdc98c 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivJsonRpcMethods.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivJsonRpcMethods.java @@ -17,6 +17,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivCreatePrivacyGroup; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivDeletePrivacyGroup; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivDistributeRawTransaction; @@ -49,16 +50,22 @@ protected RpcApi getApiGroup() { } @Override - protected Map create(final PrivacyController privacyController) { + protected Map create( + final PrivacyController privacyController, + final EnclavePublicKeyProvider enclavePublicKeyProvider) { return mapOf( new PrivGetTransactionReceipt( - getBlockchainQueries(), getPrivacyParameters(), privacyController), - new PrivCreatePrivacyGroup(privacyController), - new PrivDeletePrivacyGroup(privacyController), - new PrivFindPrivacyGroup(privacyController), + getBlockchainQueries(), + getPrivacyParameters(), + privacyController, + enclavePublicKeyProvider), + new PrivCreatePrivacyGroup(privacyController, enclavePublicKeyProvider), + new PrivDeletePrivacyGroup(privacyController, enclavePublicKeyProvider), + new PrivFindPrivacyGroup(privacyController, enclavePublicKeyProvider), new PrivGetPrivacyPrecompileAddress(getPrivacyParameters()), - new PrivGetTransactionCount(privacyController), - new PrivGetPrivateTransaction(getBlockchainQueries(), privacyController), - new PrivDistributeRawTransaction(privacyController)); + new PrivGetTransactionCount(privacyController, enclavePublicKeyProvider), + new PrivGetPrivateTransaction( + getBlockchainQueries(), privacyController, enclavePublicKeyProvider), + new PrivDistributeRawTransaction(privacyController, enclavePublicKeyProvider)); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivacyApiGroupJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivacyApiGroupJsonRpcMethods.java index 33c43b17534..10d83b91e62 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivacyApiGroupJsonRpcMethods.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivacyApiGroupJsonRpcMethods.java @@ -14,9 +14,12 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.methods; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.MultiTenancyUserUtil.enclavePublicKey; + import org.hyperledger.besu.ethereum.api.jsonrpc.LatestNonceProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.DisabledPrivacyRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.MultiTenancyRpcMethodDecorator; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Address; @@ -77,13 +80,25 @@ protected Map create() { new PrivacyController( privacyParameters, protocolSchedule.getChainId(), markerTransactionFactory); - return create(privacyController).entrySet().stream() + final EnclavePublicKeyProvider enclavePublicProvider = + privacyParameters.isMultiTenancyEnabled() + ? user -> + enclavePublicKey(user) + .orElseThrow( + () -> + new IllegalStateException( + "Request does not contain an authorization token")) + : user -> privacyParameters.getEnclavePublicKey(); + + return create(privacyController, enclavePublicProvider).entrySet().stream() .collect( Collectors.toMap( Entry::getKey, entry -> createPrivacyMethod(privacyParameters, entry.getValue()))); } - protected abstract Map create(final PrivacyController privacyController); + protected abstract Map create( + final PrivacyController privacyController, + final EnclavePublicKeyProvider enclavePublicKeyProvider); private PrivateMarkerTransactionFactory createPrivateMarkerTransactionFactory( final PrivacyParameters privacyParameters, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/privacy/eea/PrivGetEeaTransactionCountTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/privacy/eea/PrivGetEeaTransactionCountTest.java index 08b22dde297..2c748a3290a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/privacy/eea/PrivGetEeaTransactionCountTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/privacy/eea/PrivGetEeaTransactionCountTest.java @@ -20,6 +20,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivGetEeaTransactionCount; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; @@ -33,6 +34,7 @@ import org.junit.Test; public class PrivGetEeaTransactionCountTest { + private static final String ENCLAVE_PUBLIC_KEY = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; private final PrivacyParameters privacyParameters = mock(PrivacyParameters.class); private final PrivacyController privacyController = mock(PrivacyController.class); @@ -41,6 +43,7 @@ public class PrivGetEeaTransactionCountTest { private final String privateFrom = "thePrivateFromKey"; private final String[] privateFor = new String[] {"first", "second", "third"}; private final Address address = Address.fromHexString("55"); + private final EnclavePublicKeyProvider enclavePublicKeyProvider = (user) -> ENCLAVE_PUBLIC_KEY; @Before public void setup() { @@ -54,9 +57,10 @@ public void setup() { @Test public void validRequestProducesExpectedNonce() { final long reportedNonce = 8L; - final PrivGetEeaTransactionCount method = new PrivGetEeaTransactionCount(privacyController); + final PrivGetEeaTransactionCount method = + new PrivGetEeaTransactionCount(privacyController, enclavePublicKeyProvider); - when(privacyController.determineNonce(privateFrom, privateFor, address)) + when(privacyController.determineNonce(privateFrom, privateFor, address, ENCLAVE_PUBLIC_KEY)) .thenReturn(reportedNonce); final JsonRpcResponse response = method.response(request); @@ -69,9 +73,10 @@ public void validRequestProducesExpectedNonce() { @Test public void nonceProviderThrowsRuntimeExceptionProducesErrorResponse() { - final PrivGetEeaTransactionCount method = new PrivGetEeaTransactionCount(privacyController); + final PrivGetEeaTransactionCount method = + new PrivGetEeaTransactionCount(privacyController, enclavePublicKeyProvider); - when(privacyController.determineNonce(privateFrom, privateFor, address)) + when(privacyController.determineNonce(privateFrom, privateFor, address, ENCLAVE_PUBLIC_KEY)) .thenThrow(RuntimeException.class); final JsonRpcResponse response = method.response(request); @@ -84,9 +89,10 @@ public void nonceProviderThrowsRuntimeExceptionProducesErrorResponse() { @Test public void nonceProviderThrowsAnExceptionProducesErrorResponse() { - final PrivGetEeaTransactionCount method = new PrivGetEeaTransactionCount(privacyController); + final PrivGetEeaTransactionCount method = + new PrivGetEeaTransactionCount(privacyController, enclavePublicKeyProvider); - when(privacyController.determineNonce(privateFrom, privateFor, address)) + when(privacyController.determineNonce(privateFrom, privateFor, address, ENCLAVE_PUBLIC_KEY)) .thenThrow(RuntimeException.class); final JsonRpcResponse response = method.response(request); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransactionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransactionTest.java index c7372ccb3d9..a1a7bf8e7cf 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransactionTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransactionTest.java @@ -16,6 +16,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.verifyZeroInteractions; @@ -25,6 +26,7 @@ import org.hyperledger.besu.enclave.EnclaveServerException; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; @@ -42,6 +44,9 @@ import java.math.BigInteger; import java.util.Optional; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.auth.User; +import io.vertx.ext.auth.jwt.impl.JWTUser; import org.apache.tuweni.bytes.Bytes; import org.junit.Before; import org.junit.Test; @@ -106,9 +111,13 @@ public class EeaSendRawTransactionTest { Bytes.fromHexString("0x"), Address.wrap(Bytes.fromHexString("0x8411b12666f68ef74cace3615c9d5a377729d03f")), Optional.empty()); + private static final String ENCLAVE_PUBLIC_KEY = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; - final String MOCK_ORION_KEY = ""; - final String MOCK_PRIVACY_GROUP = ""; + private final String MOCK_ORION_KEY = ""; + private final String MOCK_PRIVACY_GROUP = ""; + private final User user = + new JWTUser(new JsonObject().put("privacyPublicKey", ENCLAVE_PUBLIC_KEY), ""); + private final EnclavePublicKeyProvider enclavePublicKeyProvider = (user) -> ENCLAVE_PUBLIC_KEY; @Mock private TransactionPool transactionPool; @@ -118,7 +127,8 @@ public class EeaSendRawTransactionTest { @Before public void before() { - method = new EeaSendRawTransaction(transactionPool, privacyController); + method = + new EeaSendRawTransaction(transactionPool, privacyController, enclavePublicKeyProvider); } @Test @@ -195,10 +205,10 @@ public void valueNonZeroTransaction() { @Test public void validTransactionIsSentToTransactionPool() { - when(privacyController.sendTransaction(any(PrivateTransaction.class))) + when(privacyController.sendTransaction(any(PrivateTransaction.class), any())) .thenReturn(new SendTransactionResponse(MOCK_ORION_KEY, MOCK_PRIVACY_GROUP)); when(privacyController.validatePrivateTransaction( - any(PrivateTransaction.class), any(String.class))) + any(PrivateTransaction.class), any(String.class), any())) .thenReturn(ValidationResult.valid()); when(privacyController.createPrivacyMarkerTransaction( any(String.class), any(PrivateTransaction.class))) @@ -208,7 +218,8 @@ public void validTransactionIsSentToTransactionPool() { final JsonRpcRequestContext request = new JsonRpcRequestContext( new JsonRpcRequest( - "2.0", "eea_sendRawTransaction", new String[] {VALID_PRIVATE_TRANSACTION_RLP})); + "2.0", "eea_sendRawTransaction", new String[] {VALID_PRIVATE_TRANSACTION_RLP}), + user); final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse( @@ -218,9 +229,11 @@ public void validTransactionIsSentToTransactionPool() { final JsonRpcResponse actualResponse = method.response(request); assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse); - verify(privacyController).sendTransaction(any(PrivateTransaction.class)); verify(privacyController) - .validatePrivateTransaction(any(PrivateTransaction.class), any(String.class)); + .sendTransaction(any(PrivateTransaction.class), eq(ENCLAVE_PUBLIC_KEY)); + verify(privacyController) + .validatePrivateTransaction( + any(PrivateTransaction.class), any(String.class), eq(ENCLAVE_PUBLIC_KEY)); verify(privacyController) .createPrivacyMarkerTransaction(any(String.class), any(PrivateTransaction.class)); verify(transactionPool).addLocalTransaction(any(Transaction.class)); @@ -228,10 +241,10 @@ public void validTransactionIsSentToTransactionPool() { @Test public void validTransactionPrivacyGroupIsSentToTransactionPool() { - when(privacyController.sendTransaction(any(PrivateTransaction.class))) + when(privacyController.sendTransaction(any(PrivateTransaction.class), any())) .thenReturn(new SendTransactionResponse(MOCK_ORION_KEY, MOCK_PRIVACY_GROUP)); when(privacyController.validatePrivateTransaction( - any(PrivateTransaction.class), any(String.class))) + any(PrivateTransaction.class), any(String.class), any())) .thenReturn(ValidationResult.valid()); when(privacyController.createPrivacyMarkerTransaction( any(String.class), any(PrivateTransaction.class))) @@ -254,9 +267,9 @@ public void validTransactionPrivacyGroupIsSentToTransactionPool() { final JsonRpcResponse actualResponse = method.response(request); assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse); - verify(privacyController).sendTransaction(any(PrivateTransaction.class)); + verify(privacyController).sendTransaction(any(PrivateTransaction.class), any()); verify(privacyController) - .validatePrivateTransaction(any(PrivateTransaction.class), any(String.class)); + .validatePrivateTransaction(any(PrivateTransaction.class), any(String.class), any()); verify(privacyController) .createPrivacyMarkerTransaction(any(String.class), any(PrivateTransaction.class)); verify(transactionPool).addLocalTransaction(any(Transaction.class)); @@ -282,7 +295,7 @@ public void invalidTransactionWithoutPrivateFromFieldFailsWithDecodeError() { @Test public void invalidTransactionIsNotSentToTransactionPool() { - when(privacyController.sendTransaction(any(PrivateTransaction.class))) + when(privacyController.sendTransaction(any(PrivateTransaction.class), any())) .thenThrow(new EnclaveServerException(500, "enclave failed to execute")); final JsonRpcRequestContext request = @@ -346,10 +359,10 @@ public void transactionWithNotWhitelistedSenderAccountIsRejected() { private void verifyErrorForInvalidTransaction( final TransactionInvalidReason transactionInvalidReason, final JsonRpcError expectedError) { - when(privacyController.sendTransaction(any(PrivateTransaction.class))) + when(privacyController.sendTransaction(any(PrivateTransaction.class), any())) .thenReturn(new SendTransactionResponse(MOCK_ORION_KEY, MOCK_PRIVACY_GROUP)); when(privacyController.validatePrivateTransaction( - any(PrivateTransaction.class), any(String.class))) + any(PrivateTransaction.class), any(String.class), any())) .thenReturn(ValidationResult.valid()); when(privacyController.createPrivacyMarkerTransaction( any(String.class), any(PrivateTransaction.class))) @@ -367,9 +380,9 @@ private void verifyErrorForInvalidTransaction( final JsonRpcResponse actualResponse = method.response(request); assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse); - verify(privacyController).sendTransaction(any(PrivateTransaction.class)); + verify(privacyController).sendTransaction(any(PrivateTransaction.class), any()); verify(privacyController) - .validatePrivateTransaction(any(PrivateTransaction.class), any(String.class)); + .validatePrivateTransaction(any(PrivateTransaction.class), any(String.class), any()); verify(privacyController) .createPrivacyMarkerTransaction(any(String.class), any(PrivateTransaction.class)); verify(transactionPool).addLocalTransaction(any(Transaction.class)); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCreatePrivacyGroupTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCreatePrivacyGroupTest.java index c23ba26b34a..2f4030dfa88 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCreatePrivacyGroupTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCreatePrivacyGroupTest.java @@ -18,6 +18,7 @@ import static org.assertj.core.api.Assertions.catchThrowableOfType; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.hyperledger.besu.enclave.Enclave; @@ -26,6 +27,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.parameters.CreatePrivacyGroupParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; @@ -35,6 +37,9 @@ import java.util.List; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.auth.User; +import io.vertx.ext.auth.jwt.impl.JWTUser; import org.assertj.core.util.Lists; import org.junit.Before; import org.junit.Test; @@ -45,10 +50,14 @@ public class PrivCreatePrivacyGroupTest { private static final String NAME = "testName"; private static final String DESCRIPTION = "testDesc"; private static final List ADDRESSES = Lists.newArrayList(FROM, "second participant"); + private static final String ENCLAVE_PUBLIC_KEY = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; private final Enclave enclave = mock(Enclave.class); private final PrivacyParameters privacyParameters = mock(PrivacyParameters.class); private final PrivacyController privacyController = mock(PrivacyController.class); + private final User user = + new JWTUser(new JsonObject().put("privacyPublicKey", ENCLAVE_PUBLIC_KEY), ""); + private final EnclavePublicKeyProvider enclavePublicKeyProvider = (user) -> ENCLAVE_PUBLIC_KEY; @Before public void setUp() { @@ -61,12 +70,12 @@ public void verifyCreatePrivacyGroup() { final String expected = "a wonderful group"; final PrivacyGroup privacyGroup = new PrivacyGroup(expected, PrivacyGroup.Type.PANTHEON, NAME, DESCRIPTION, ADDRESSES); - when(privacyController.createPrivacyGroup(ADDRESSES, NAME, DESCRIPTION)) + when(privacyController.createPrivacyGroup(ADDRESSES, NAME, DESCRIPTION, ENCLAVE_PUBLIC_KEY)) .thenReturn(privacyGroup); when(privacyParameters.getEnclavePublicKey()).thenReturn(FROM); final PrivCreatePrivacyGroup privCreatePrivacyGroup = - new PrivCreatePrivacyGroup(privacyController); + new PrivCreatePrivacyGroup(privacyController, enclavePublicKeyProvider); final CreatePrivacyGroupParameter param = new CreatePrivacyGroupParameter(ADDRESSES, NAME, DESCRIPTION); @@ -74,7 +83,7 @@ public void verifyCreatePrivacyGroup() { final Object[] params = new Object[] {param}; final JsonRpcRequestContext request = - new JsonRpcRequestContext(new JsonRpcRequest("1", "priv_createPrivacyGroup", params)); + new JsonRpcRequestContext(new JsonRpcRequest("1", "priv_createPrivacyGroup", params), user); final JsonRpcSuccessResponse response = (JsonRpcSuccessResponse) privCreatePrivacyGroup.response(request); @@ -82,6 +91,7 @@ public void verifyCreatePrivacyGroup() { final String result = (String) response.getResult(); assertThat(result).isEqualTo(expected); + verify(privacyController).createPrivacyGroup(ADDRESSES, NAME, DESCRIPTION, ENCLAVE_PUBLIC_KEY); } @Test @@ -89,11 +99,12 @@ public void verifyCreatePrivacyGroupWithoutDescription() { final String expected = "a wonderful group"; final PrivacyGroup privacyGroup = new PrivacyGroup(expected, PrivacyGroup.Type.PANTHEON, NAME, DESCRIPTION, ADDRESSES); - when(privacyController.createPrivacyGroup(ADDRESSES, NAME, null)).thenReturn(privacyGroup); + when(privacyController.createPrivacyGroup(ADDRESSES, NAME, null, ENCLAVE_PUBLIC_KEY)) + .thenReturn(privacyGroup); when(privacyParameters.getEnclavePublicKey()).thenReturn(FROM); final PrivCreatePrivacyGroup privCreatePrivacyGroup = - new PrivCreatePrivacyGroup(privacyController); + new PrivCreatePrivacyGroup(privacyController, enclavePublicKeyProvider); final Object[] params = new Object[] { @@ -124,12 +135,12 @@ public void verifyCreatePrivacyGroupWithoutName() { final String expected = "a wonderful group"; final PrivacyGroup privacyGroup = new PrivacyGroup(expected, PrivacyGroup.Type.PANTHEON, NAME, DESCRIPTION, ADDRESSES); - when(privacyController.createPrivacyGroup(ADDRESSES, null, DESCRIPTION)) + when(privacyController.createPrivacyGroup(ADDRESSES, null, DESCRIPTION, ENCLAVE_PUBLIC_KEY)) .thenReturn(privacyGroup); when(privacyParameters.getEnclavePublicKey()).thenReturn(FROM); final PrivCreatePrivacyGroup privCreatePrivacyGroup = - new PrivCreatePrivacyGroup(privacyController); + new PrivCreatePrivacyGroup(privacyController, enclavePublicKeyProvider); final Object[] params = new Object[] { @@ -160,11 +171,12 @@ public void verifyCreatePrivacyGroupWithoutOptionalParams() { final String expected = "a wonderful group"; final PrivacyGroup privacyGroup = new PrivacyGroup(expected, PrivacyGroup.Type.PANTHEON, NAME, DESCRIPTION, ADDRESSES); - when(privacyController.createPrivacyGroup(ADDRESSES, null, null)).thenReturn(privacyGroup); + when(privacyController.createPrivacyGroup(ADDRESSES, null, null, ENCLAVE_PUBLIC_KEY)) + .thenReturn(privacyGroup); when(privacyParameters.getEnclavePublicKey()).thenReturn(FROM); final PrivCreatePrivacyGroup privCreatePrivacyGroup = - new PrivCreatePrivacyGroup(privacyController); + new PrivCreatePrivacyGroup(privacyController, enclavePublicKeyProvider); final Object[] params = new Object[] { @@ -196,7 +208,7 @@ public void returnsCorrectExceptionInvalidParam() { when(privacyParameters.getEnclavePublicKey()).thenReturn(FROM); final PrivCreatePrivacyGroup privCreatePrivacyGroup = - new PrivCreatePrivacyGroup(privacyController); + new PrivCreatePrivacyGroup(privacyController, enclavePublicKeyProvider); final Object[] params = new Object[] { @@ -225,7 +237,7 @@ public String getDescription() { public void returnsCorrectExceptionMissingParam() { final PrivCreatePrivacyGroup privCreatePrivacyGroup = - new PrivCreatePrivacyGroup(privacyController); + new PrivCreatePrivacyGroup(privacyController, enclavePublicKeyProvider); final Object[] params = new Object[] {}; @@ -241,10 +253,10 @@ public void returnsCorrectExceptionMissingParam() { @Test public void returnsCorrectErrorEnclaveError() { - when(privacyController.createPrivacyGroup(ADDRESSES, NAME, DESCRIPTION)) + when(privacyController.createPrivacyGroup(ADDRESSES, NAME, DESCRIPTION, ENCLAVE_PUBLIC_KEY)) .thenThrow(new EnclaveServerException(500, "")); final PrivCreatePrivacyGroup privCreatePrivacyGroup = - new PrivCreatePrivacyGroup(privacyController); + new PrivCreatePrivacyGroup(privacyController, enclavePublicKeyProvider); final CreatePrivacyGroupParameter param = new CreatePrivacyGroupParameter(ADDRESSES, NAME, DESCRIPTION); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDeletePrivacyGroupTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDeletePrivacyGroupTest.java new file mode 100644 index 00000000000..a7c92679886 --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDeletePrivacyGroupTest.java @@ -0,0 +1,88 @@ +/* + * 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.ethereum.api.jsonrpc.internal.privacy.methods.priv; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.enclave.Enclave; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.core.PrivacyParameters; +import org.hyperledger.besu.ethereum.privacy.PrivacyController; + +import io.vertx.core.json.JsonObject; +import io.vertx.ext.auth.User; +import io.vertx.ext.auth.jwt.impl.JWTUser; +import org.junit.Before; +import org.junit.Test; + +public class PrivDeletePrivacyGroupTest { + private static final String ENCLAVE_PUBLIC_KEY = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; + private static final String PRIVACY_GROUP_ID = "privacyGroupId"; + + private final Enclave enclave = mock(Enclave.class); + private final PrivacyParameters privacyParameters = mock(PrivacyParameters.class); + private final PrivacyController privacyController = mock(PrivacyController.class); + private final User user = + new JWTUser(new JsonObject().put("privacyPublicKey", ENCLAVE_PUBLIC_KEY), ""); + private final EnclavePublicKeyProvider enclavePublicKeyProvider = (user) -> ENCLAVE_PUBLIC_KEY; + private JsonRpcRequestContext request; + + @Before + public void setUp() { + when(privacyParameters.getEnclave()).thenReturn(enclave); + when(privacyParameters.isEnabled()).thenReturn(true); + request = + new JsonRpcRequestContext( + new JsonRpcRequest("1", "priv_deletePrivacyGroup", new Object[] {PRIVACY_GROUP_ID}), + user); + } + + @Test + public void deletesPrivacyGroupWithValidGroupId() { + when(privacyController.deletePrivacyGroup(PRIVACY_GROUP_ID, ENCLAVE_PUBLIC_KEY)) + .thenReturn(PRIVACY_GROUP_ID); + + final PrivDeletePrivacyGroup privDeletePrivacyGroup = + new PrivDeletePrivacyGroup(privacyController, enclavePublicKeyProvider); + + final JsonRpcSuccessResponse response = + (JsonRpcSuccessResponse) privDeletePrivacyGroup.response(request); + final String result = (String) response.getResult(); + assertThat(result).isEqualTo(PRIVACY_GROUP_ID); + verify(privacyController).deletePrivacyGroup(PRIVACY_GROUP_ID, ENCLAVE_PUBLIC_KEY); + } + + @Test + public void failsWithDeletePrivacyGroupErrorIfEnclaveFails() { + when(privacyController.deletePrivacyGroup(PRIVACY_GROUP_ID, ENCLAVE_PUBLIC_KEY)) + .thenThrow(new IllegalStateException("some failure")); + + final PrivDeletePrivacyGroup privDeletePrivacyGroup = + new PrivDeletePrivacyGroup(privacyController, enclavePublicKeyProvider); + + final JsonRpcErrorResponse response = + (JsonRpcErrorResponse) privDeletePrivacyGroup.response(request); + assertThat(response.getError()).isEqualTo(JsonRpcError.DELETE_PRIVACY_GROUP_ERROR); + verify(privacyController).deletePrivacyGroup(PRIVACY_GROUP_ID, ENCLAVE_PUBLIC_KEY); + } +} diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransactionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransactionTest.java index 3797fb73503..839ad3c6fcf 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransactionTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransactionTest.java @@ -16,11 +16,13 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; @@ -30,6 +32,9 @@ import java.util.Base64; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.auth.User; +import io.vertx.ext.auth.jwt.impl.JWTUser; import org.apache.tuweni.bytes.Bytes; import org.junit.Before; import org.junit.Test; @@ -48,22 +53,27 @@ public class PrivDistributeRawTransactionTest { + "e60551d7a19cf30603db5bfc23e5ac43a56f57f25f75486aa00f" + "200e885ff29e973e2576b6600181d1b0a2b5294e30d9be4a1981" + "ffb33a0b8c8a72657374726963746564"; + private static final String ENCLAVE_PUBLIC_KEY = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; + + private final User user = + new JWTUser(new JsonObject().put("privacyPublicKey", ENCLAVE_PUBLIC_KEY), ""); + private final EnclavePublicKeyProvider enclavePublicKeyProvider = (user) -> ENCLAVE_PUBLIC_KEY; @Mock private PrivDistributeRawTransaction method; @Mock private PrivacyController privacyController; @Before public void before() { - method = new PrivDistributeRawTransaction(privacyController); + method = new PrivDistributeRawTransaction(privacyController, enclavePublicKeyProvider); } @Test public void validTransactionHashReturnedAfterDistribute() { final String enclavePublicKey = "93Ky7lXwFkMc7+ckoFgUMku5bpr9tz4zhmWmk9RlNng="; - when(privacyController.sendTransaction(any(PrivateTransaction.class))) + when(privacyController.sendTransaction(any(PrivateTransaction.class), any())) .thenReturn(new SendTransactionResponse(enclavePublicKey, "")); when(privacyController.validatePrivateTransaction( - any(PrivateTransaction.class), any(String.class))) + any(PrivateTransaction.class), any(String.class), any())) .thenReturn(ValidationResult.valid()); final JsonRpcRequestContext request = @@ -71,7 +81,8 @@ public void validTransactionHashReturnedAfterDistribute() { new JsonRpcRequest( "2.0", "priv_distributeRawTransaction", - new String[] {VALID_PRIVATE_TRANSACTION_RLP_PRIVACY_GROUP})); + new String[] {VALID_PRIVATE_TRANSACTION_RLP_PRIVACY_GROUP}), + user); final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse( @@ -81,8 +92,10 @@ public void validTransactionHashReturnedAfterDistribute() { final JsonRpcResponse actualResponse = method.response(request); assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse); - verify(privacyController).sendTransaction(any(PrivateTransaction.class)); verify(privacyController) - .validatePrivateTransaction(any(PrivateTransaction.class), any(String.class)); + .sendTransaction(any(PrivateTransaction.class), eq(ENCLAVE_PUBLIC_KEY)); + verify(privacyController) + .validatePrivateTransaction( + any(PrivateTransaction.class), any(String.class), eq(ENCLAVE_PUBLIC_KEY)); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivFindPrivacyGroupTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivFindPrivacyGroupTest.java new file mode 100644 index 00000000000..1ae33a30d21 --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivFindPrivacyGroupTest.java @@ -0,0 +1,101 @@ +/* + * 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.ethereum.api.jsonrpc.internal.privacy.methods.priv; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.enclave.Enclave; +import org.hyperledger.besu.enclave.types.PrivacyGroup; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.core.PrivacyParameters; +import org.hyperledger.besu.ethereum.privacy.PrivacyController; + +import java.util.List; + +import io.vertx.core.json.JsonObject; +import io.vertx.ext.auth.User; +import io.vertx.ext.auth.jwt.impl.JWTUser; +import org.assertj.core.util.Lists; +import org.junit.Before; +import org.junit.Test; + +public class PrivFindPrivacyGroupTest { + private static final String ENCLAVE_PUBLIC_KEY = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; + private static final List ADDRESSES = + List.of( + "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", + "0x627306090abab3a6e1400e9345bc60c78a8bef57"); + + private final Enclave enclave = mock(Enclave.class); + private final PrivacyParameters privacyParameters = mock(PrivacyParameters.class); + private final PrivacyController privacyController = mock(PrivacyController.class); + private final User user = + new JWTUser(new JsonObject().put("privacyPublicKey", ENCLAVE_PUBLIC_KEY), ""); + private final EnclavePublicKeyProvider enclavePublicKeyProvider = (user) -> ENCLAVE_PUBLIC_KEY; + + private JsonRpcRequestContext request; + private PrivacyGroup privacyGroup; + + @Before + public void setUp() { + when(privacyParameters.getEnclave()).thenReturn(enclave); + when(privacyParameters.isEnabled()).thenReturn(true); + request = + new JsonRpcRequestContext( + new JsonRpcRequest("1", "priv_deletePrivacyGroup", new Object[] {ADDRESSES}), user); + privacyGroup = new PrivacyGroup(); + privacyGroup.setName("privacyGroup"); + privacyGroup.setDescription("privacyGroup desc"); + privacyGroup.setPrivacyGroupId("privacy group id"); + privacyGroup.setMembers(Lists.list("member1")); + } + + @Test + public void findsPrivacyGroupWithValidAddresses() { + when(privacyController.findPrivacyGroup(ADDRESSES, ENCLAVE_PUBLIC_KEY)) + .thenReturn(new PrivacyGroup[] {privacyGroup}); + + final PrivFindPrivacyGroup privFindPrivacyGroup = + new PrivFindPrivacyGroup(privacyController, enclavePublicKeyProvider); + + final JsonRpcSuccessResponse response = + (JsonRpcSuccessResponse) privFindPrivacyGroup.response(request); + final PrivacyGroup[] result = (PrivacyGroup[]) response.getResult(); + assertThat(result).hasSize(1); + assertThat(result[0]).isEqualToComparingFieldByField(privacyGroup); + verify(privacyController).findPrivacyGroup(ADDRESSES, ENCLAVE_PUBLIC_KEY); + } + + @Test + public void failsWithFindPrivacyGroupErrorIfEnclaveFails() { + when(privacyController.findPrivacyGroup(ADDRESSES, ENCLAVE_PUBLIC_KEY)) + .thenThrow(new IllegalStateException("some failure")); + final PrivFindPrivacyGroup privFindPrivacyGroup = + new PrivFindPrivacyGroup(privacyController, enclavePublicKeyProvider); + + final JsonRpcErrorResponse response = + (JsonRpcErrorResponse) privFindPrivacyGroup.response(request); + assertThat(response.getError()).isEqualTo(JsonRpcError.FIND_PRIVACY_GROUP_ERROR); + verify(privacyController).findPrivacyGroup(ADDRESSES, ENCLAVE_PUBLIC_KEY); + } +} diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransactionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransactionTest.java index 202770dc964..9f610f724dd 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransactionTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransactionTest.java @@ -19,6 +19,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.hyperledger.besu.crypto.SECP256K1; @@ -26,6 +27,7 @@ import org.hyperledger.besu.enclave.types.ReceiveResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.PrivateTransactionGroupResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.PrivateTransactionLegacyResult; @@ -48,6 +50,9 @@ import java.util.Optional; import com.google.common.collect.Lists; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.auth.User; +import io.vertx.ext.auth.jwt.impl.JWTUser; import org.apache.tuweni.bytes.Bytes; import org.junit.Before; import org.junit.Rule; @@ -65,6 +70,11 @@ public class PrivGetPrivateTransactionTest { SECP256K1.PrivateKey.create( new BigInteger( "8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", 16))); + private static final String ENCLAVE_PUBLIC_KEY = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; + private static final String TRANSACTION_HASH = + Bytes.fromBase64String("5bpr9tz4zhmWmk9RlNng93Ky7lXwFkMc7+ckoFgUMku=").toString(); + private static final Bytes ENCLAVE_KEY = + Bytes.fromBase64String("93Ky7lXwFkMc7+ckoFgUMku5bpr9tz4zhmWmk9RlNng="); private final PrivateTransaction.Builder privateTransactionBuilder = PrivateTransaction.builder() @@ -90,15 +100,15 @@ public class PrivGetPrivateTransactionTest { .privateFrom(Bytes.fromBase64String("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=")) .restriction(Restriction.RESTRICTED); - private final String enclaveKey = - Bytes.fromBase64String("93Ky7lXwFkMc7+ckoFgUMku5bpr9tz4zhmWmk9RlNng=").toString(); - private final Enclave enclave = mock(Enclave.class); private final PrivacyParameters privacyParameters = mock(PrivacyParameters.class); private final BlockchainQueries blockchain = mock(BlockchainQueries.class); private final TransactionWithMetadata returnedTransaction = mock(TransactionWithMetadata.class); private final Transaction justTransaction = mock(Transaction.class); private final PrivacyController privacyController = mock(PrivacyController.class); + private final User user = + new JWTUser(new JsonObject().put("privacyPublicKey", ENCLAVE_PUBLIC_KEY), ""); + private final EnclavePublicKeyProvider enclavePublicKeyProvider = (user) -> ENCLAVE_PUBLIC_KEY; @Before public void before() { @@ -111,8 +121,7 @@ public void returnsPrivateTransactionLegacy() { when(blockchain.transactionByHash(any(Hash.class))) .thenReturn(Optional.of(returnedTransaction)); when(returnedTransaction.getTransaction()).thenReturn(justTransaction); - when(justTransaction.getPayload()) - .thenReturn(new UnformattedDataImpl(Bytes.fromBase64String(""))); + when(justTransaction.getPayload()).thenReturn(new UnformattedDataImpl(ENCLAVE_KEY)); final PrivateTransaction privateTransaction = privateTransactionBuilder @@ -124,14 +133,15 @@ public void returnsPrivateTransactionLegacy() { new PrivateTransactionLegacyResult(privateTransaction); final PrivGetPrivateTransaction privGetPrivateTransaction = - new PrivGetPrivateTransaction(blockchain, privacyController); - final Object[] params = new Object[] {enclaveKey}; + new PrivGetPrivateTransaction(blockchain, privacyController, enclavePublicKeyProvider); + final Object[] params = new Object[] {TRANSACTION_HASH}; final JsonRpcRequestContext request = - new JsonRpcRequestContext(new JsonRpcRequest("1", "priv_getPrivateTransaction", params)); + new JsonRpcRequestContext( + new JsonRpcRequest("1", "priv_getPrivateTransaction", params), user); final BytesValueRLPOutput bvrlp = new BytesValueRLPOutput(); privateTransaction.writeTo(bvrlp); - when(privacyController.retrieveTransaction(anyString())) + when(privacyController.retrieveTransaction(anyString(), any())) .thenReturn( new ReceiveResponse( Base64.getEncoder().encodeToString(bvrlp.encoded().toArray()).getBytes(UTF_8), "")); @@ -140,6 +150,7 @@ public void returnsPrivateTransactionLegacy() { final PrivateTransactionResult result = (PrivateTransactionResult) response.getResult(); assertThat(result).isEqualToComparingFieldByField(privateTransactionLegacyResult); + verify(privacyController).retrieveTransaction(ENCLAVE_KEY.toBase64String(), ENCLAVE_PUBLIC_KEY); } @Test @@ -158,15 +169,15 @@ public void returnsPrivateTransactionGroup() { new PrivateTransactionGroupResult(privateTransaction); final PrivGetPrivateTransaction privGetPrivateTransaction = - new PrivGetPrivateTransaction(blockchain, privacyController); + new PrivGetPrivateTransaction(blockchain, privacyController, enclavePublicKeyProvider); - final Object[] params = new Object[] {enclaveKey}; + final Object[] params = new Object[] {TRANSACTION_HASH}; final JsonRpcRequestContext request = new JsonRpcRequestContext(new JsonRpcRequest("1", "priv_getPrivateTransaction", params)); final BytesValueRLPOutput bvrlp = new BytesValueRLPOutput(); privateTransaction.writeTo(bvrlp); - when(privacyController.retrieveTransaction(anyString())) + when(privacyController.retrieveTransaction(anyString(), any())) .thenReturn( new ReceiveResponse( Base64.getEncoder().encodeToString(bvrlp.encoded().toArrayUnsafe()).getBytes(UTF_8), diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionCountTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionCountTest.java index b45195dd89f..4060aab333e 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionCountTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionCountTest.java @@ -17,21 +17,27 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.privacy.PrivacyController; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.auth.User; +import io.vertx.ext.auth.jwt.impl.JWTUser; import org.apache.tuweni.bytes.Bytes; import org.junit.Before; import org.junit.Test; public class PrivGetTransactionCountTest { + private static final String ENCLAVE_PUBLIC_KEY = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; private final PrivacyParameters privacyParameters = mock(PrivacyParameters.class); private final PrivacyController privacyController = mock(PrivacyController.class); @@ -40,25 +46,30 @@ public class PrivGetTransactionCountTest { private final Address senderAddress = Address.fromHexString("0x627306090abab3a6e1400e9345bc60c78a8bef57"); private final long NONCE = 5; + private User user = new JWTUser(new JsonObject().put("privacyPublicKey", ENCLAVE_PUBLIC_KEY), ""); + private final EnclavePublicKeyProvider enclavePublicKeyProvider = (user) -> ENCLAVE_PUBLIC_KEY; @Before public void before() { when(privacyParameters.isEnabled()).thenReturn(true); - when(privacyController.determineNonce(senderAddress, privacyGroupId)).thenReturn(NONCE); + when(privacyController.determineNonce(senderAddress, privacyGroupId, ENCLAVE_PUBLIC_KEY)) + .thenReturn(NONCE); } @Test public void verifyTransactionCount() { final PrivGetTransactionCount privGetTransactionCount = - new PrivGetTransactionCount(privacyController); + new PrivGetTransactionCount(privacyController, enclavePublicKeyProvider); final Object[] params = new Object[] {senderAddress, privacyGroupId}; final JsonRpcRequestContext request = - new JsonRpcRequestContext(new JsonRpcRequest("1", "priv_getTransactionCount", params)); + new JsonRpcRequestContext( + new JsonRpcRequest("1", "priv_getTransactionCount", params), user); final JsonRpcSuccessResponse response = (JsonRpcSuccessResponse) privGetTransactionCount.response(request); assertThat(response.getResult()).isEqualTo(String.format("0x%X", NONCE)); + verify(privacyController).determineNonce(senderAddress, privacyGroupId, ENCLAVE_PUBLIC_KEY); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceiptTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceiptTest.java index 60fd9024cb6..a8552f67557 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceiptTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceiptTest.java @@ -21,6 +21,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.hyperledger.besu.crypto.SECP256K1; @@ -29,6 +30,7 @@ import org.hyperledger.besu.enclave.types.ReceiveResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.PrivateTransactionReceiptResult; @@ -54,6 +56,9 @@ import java.util.Optional; import com.google.common.collect.Lists; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.auth.User; +import io.vertx.ext.auth.jwt.impl.JWTUser; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.junit.Before; @@ -65,6 +70,8 @@ public class PrivGetTransactionReceiptTest { @Rule public final TemporaryFolder temp = new TemporaryFolder(); + private static final String ENCLAVE_PUBLIC_KEY = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; + private static final Bytes ENCLAVE_KEY = Bytes.wrap("EnclaveKey".getBytes(UTF_8)); private static final Address SENDER = Address.fromHexString("0xfe3b557e8fb62b89f4916b721be55ceb828dbd73"); @@ -135,6 +142,9 @@ public class PrivGetTransactionReceiptTest { null, Quantity.create(Bytes.of(1).toUnsignedBigInteger())); + private User user = new JWTUser(new JsonObject().put("privacyPublicKey", ENCLAVE_PUBLIC_KEY), ""); + private final EnclavePublicKeyProvider enclavePublicKeyProvider = (user) -> ENCLAVE_PUBLIC_KEY; + private final BlockchainQueries blockchainQueries = mock(BlockchainQueries.class); private final Blockchain blockchain = mock(Blockchain.class); private final PrivacyParameters privacyParameters = mock(PrivacyParameters.class); @@ -143,7 +153,7 @@ public class PrivGetTransactionReceiptTest { @Before public void setUp() { - when(privacyController.retrieveTransaction(anyString())) + when(privacyController.retrieveTransaction(anyString(), any())) .thenReturn( new ReceiveResponse( Base64.getEncoder().encode(RLP.encode(privateTransaction::writeTo).toArray()), "")); @@ -170,10 +180,12 @@ public void setUp() { public void returnReceiptIfTransactionExists() { final PrivGetTransactionReceipt privGetTransactionReceipt = - new PrivGetTransactionReceipt(blockchainQueries, privacyParameters, privacyController); + new PrivGetTransactionReceipt( + blockchainQueries, privacyParameters, privacyController, enclavePublicKeyProvider); final Object[] params = new Object[] {transaction.getHash()}; final JsonRpcRequestContext request = - new JsonRpcRequestContext(new JsonRpcRequest("1", "priv_getTransactionReceipt", params)); + new JsonRpcRequestContext( + new JsonRpcRequest("1", "priv_getTransactionReceipt", params), user); final JsonRpcSuccessResponse response = (JsonRpcSuccessResponse) privGetTransactionReceipt.response(request); @@ -181,15 +193,17 @@ public void returnReceiptIfTransactionExists() { (PrivateTransactionReceiptResult) response.getResult(); assertThat(result).isEqualToComparingFieldByField(expectedResult); + verify(privacyController).retrieveTransaction(ENCLAVE_KEY.toBase64String(), ENCLAVE_PUBLIC_KEY); } @Test public void enclavePayloadNotFoundResultsInSuccessButNullResponse() { - when(privacyController.retrieveTransaction(anyString())) + when(privacyController.retrieveTransaction(anyString(), any())) .thenThrow(new EnclaveClientException(404, "EnclavePayloadNotFound")); final PrivGetTransactionReceipt privGetTransactionReceipt = - new PrivGetTransactionReceipt(blockchainQueries, privacyParameters, privacyController); + new PrivGetTransactionReceipt( + blockchainQueries, privacyParameters, privacyController, enclavePublicKeyProvider); final Object[] params = new Object[] {transaction.getHash()}; final JsonRpcRequestContext request = new JsonRpcRequestContext(new JsonRpcRequest("1", "priv_getTransactionReceipt", params)); @@ -207,7 +221,8 @@ public void markerTransactionNotAvailableResultsInNullResponse() { when(blockchain.getTransactionLocation(nullable(Hash.class))).thenReturn(Optional.empty()); final PrivGetTransactionReceipt privGetTransactionReceipt = - new PrivGetTransactionReceipt(blockchainQueries, privacyParameters, privacyController); + new PrivGetTransactionReceipt( + blockchainQueries, privacyParameters, privacyController, enclavePublicKeyProvider); final Object[] params = new Object[] {transaction.getHash()}; final JsonRpcRequestContext request = new JsonRpcRequestContext(new JsonRpcRequest("1", "priv_getTransactionReceipt", params)); @@ -222,10 +237,11 @@ public void markerTransactionNotAvailableResultsInNullResponse() { @Test public void enclaveConnectionIssueThrowsRuntimeException() { - when(privacyController.retrieveTransaction(anyString())) + when(privacyController.retrieveTransaction(anyString(), any())) .thenThrow(EnclaveServerException.class); final PrivGetTransactionReceipt privGetTransactionReceipt = - new PrivGetTransactionReceipt(blockchainQueries, privacyParameters, privacyController); + new PrivGetTransactionReceipt( + blockchainQueries, privacyParameters, privacyController, enclavePublicKeyProvider); final Object[] params = new Object[] {transaction.getHash()}; final JsonRpcRequestContext request = new JsonRpcRequestContext(new JsonRpcRequest("1", "priv_getTransactionReceipt", params)); @@ -240,7 +256,8 @@ public void transactionReceiptContainsRevertReasonWhenInvalidTransactionOccurs() .thenReturn(Optional.of(Bytes.fromHexString("0x01"))); final PrivGetTransactionReceipt privGetTransactionReceipt = - new PrivGetTransactionReceipt(blockchainQueries, privacyParameters, privacyController); + new PrivGetTransactionReceipt( + blockchainQueries, privacyParameters, privacyController, enclavePublicKeyProvider); final Object[] params = new Object[] {transaction.getHash()}; final JsonRpcRequest request = new JsonRpcRequest("1", "priv_getTransactionReceipt", params); @@ -256,11 +273,12 @@ public void transactionReceiptContainsRevertReasonWhenInvalidTransactionOccurs() @Test public void enclaveKeysCannotDecryptPayloadThrowsRuntimeException() { final String keysCannotDecryptPayloadMsg = "EnclaveKeysCannotDecryptPayload"; - when(privacyController.retrieveTransaction(any())) + when(privacyController.retrieveTransaction(any(), any())) .thenThrow(new EnclaveClientException(400, keysCannotDecryptPayloadMsg)); final PrivGetTransactionReceipt privGetTransactionReceipt = - new PrivGetTransactionReceipt(blockchainQueries, privacyParameters, privacyController); + new PrivGetTransactionReceipt( + blockchainQueries, privacyParameters, privacyController, enclavePublicKeyProvider); final Object[] params = new Object[] {transaction.getHash()}; final JsonRpcRequestContext request = new JsonRpcRequestContext(new JsonRpcRequest("1", "priv_getTransactionReceipt", params)); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivacyApiGroupJsonRpcMethodsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivacyApiGroupJsonRpcMethodsTest.java index 61534db1509..d1d47d15757 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivacyApiGroupJsonRpcMethodsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivacyApiGroupJsonRpcMethodsTest.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.methods; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.PRIVACY_NOT_ENABLED; import static org.mockito.Mockito.when; @@ -23,6 +24,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.MultiTenancyRpcMethodDecorator; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; @@ -34,7 +36,11 @@ import org.hyperledger.besu.ethereum.privacy.PrivacyController; import java.util.Map; +import java.util.Optional; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.auth.User; +import io.vertx.ext.auth.jwt.impl.JWTUser; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -43,18 +49,23 @@ @RunWith(MockitoJUnitRunner.class) public class PrivacyApiGroupJsonRpcMethodsTest { + private static final String DEFAULT_ENCLAVE_PUBLIC_KEY = + "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; + @Mock private JsonRpcMethod rpcMethod; @Mock private BlockchainQueries blockchainQueries; @Mock private ProtocolSchedule protocolSchedule; @Mock private TransactionPool transactionPool; @Mock private PrivacyParameters privacyParameters; - private PrivacyApiGroupJsonRpcMethods privacyApiGroupJsonRpcMethods; + private TestPrivacyApiGroupJsonRpcMethods privacyApiGroupJsonRpcMethods; @Before public void setup() { when(rpcMethod.getName()).thenReturn("priv_method"); - privacyApiGroupJsonRpcMethods = createPrivacyApiGroupJsonRpcMethods(); + privacyApiGroupJsonRpcMethods = + new TestPrivacyApiGroupJsonRpcMethods( + blockchainQueries, protocolSchedule, transactionPool, privacyParameters, rpcMethod); } @Test @@ -75,6 +86,52 @@ public void rpcsCreatedWithoutMultiTenancyUseOriginalRpcMethod() { assertThat(privMethod).isSameAs(rpcMethod); } + @Test + public void rpcsCreatedWithoutMultiTenancyUseFixedEnclavePublicKey() { + when(privacyParameters.isEnabled()).thenReturn(true); + when(privacyParameters.getEnclavePublicKey()).thenReturn(DEFAULT_ENCLAVE_PUBLIC_KEY); + + final User user = createUser(DEFAULT_ENCLAVE_PUBLIC_KEY); + privacyApiGroupJsonRpcMethods.create(); + final EnclavePublicKeyProvider enclavePublicKeyProvider = + privacyApiGroupJsonRpcMethods.enclavePublicKeyProvider; + + assertThat(enclavePublicKeyProvider.getEnclaveKey(Optional.of(user))) + .isEqualTo(DEFAULT_ENCLAVE_PUBLIC_KEY); + assertThat(enclavePublicKeyProvider.getEnclaveKey(Optional.empty())) + .isEqualTo(DEFAULT_ENCLAVE_PUBLIC_KEY); + } + + @Test + public void rpcsCreatedWithMultiTenancyUseEnclavePublicKeyFromRequest() { + when(privacyParameters.isEnabled()).thenReturn(true); + when(privacyParameters.isMultiTenancyEnabled()).thenReturn(true); + + final User user1 = createUser("key1"); + final User user2 = createUser("key2"); + + privacyApiGroupJsonRpcMethods.create(); + final EnclavePublicKeyProvider enclavePublicKeyProvider = + privacyApiGroupJsonRpcMethods.enclavePublicKeyProvider; + + assertThat(enclavePublicKeyProvider.getEnclaveKey(Optional.of(user1))).isEqualTo("key1"); + assertThat(enclavePublicKeyProvider.getEnclaveKey(Optional.of(user2))).isEqualTo("key2"); + } + + @Test + public void rpcsCreatedWithMultiTenancyAndWithoutUserFail() { + when(privacyParameters.isEnabled()).thenReturn(true); + when(privacyParameters.isMultiTenancyEnabled()).thenReturn(true); + + privacyApiGroupJsonRpcMethods.create(); + final EnclavePublicKeyProvider enclavePublicKeyProvider = + privacyApiGroupJsonRpcMethods.enclavePublicKeyProvider; + + assertThatThrownBy(() -> enclavePublicKeyProvider.getEnclaveKey(Optional.empty())) + .isInstanceOf(IllegalStateException.class) + .hasMessage("Request does not contain an authorization token"); + } + @Test public void rpcMethodsCreatedWhenPrivacyIsNotEnabledAreDisabled() { final Map rpcMethods = privacyApiGroupJsonRpcMethods.create(); @@ -90,19 +147,36 @@ public void rpcMethodsCreatedWhenPrivacyIsNotEnabledAreDisabled() { assertThat(errorResponse.getError()).isEqualTo(PRIVACY_NOT_ENABLED); } - private PrivacyApiGroupJsonRpcMethods createPrivacyApiGroupJsonRpcMethods() { - return new PrivacyApiGroupJsonRpcMethods( - blockchainQueries, protocolSchedule, transactionPool, privacyParameters) { - - @Override - protected RpcApi getApiGroup() { - return RpcApis.PRIV; - } + private User createUser(final String enclavePublicKey) { + return new JWTUser(new JsonObject().put("privacyPublicKey", enclavePublicKey), ""); + } - @Override - protected Map create(final PrivacyController privacyController) { - return mapOf(rpcMethod); - } - }; + private static class TestPrivacyApiGroupJsonRpcMethods extends PrivacyApiGroupJsonRpcMethods { + + private final JsonRpcMethod rpcMethod; + private EnclavePublicKeyProvider enclavePublicKeyProvider; + + public TestPrivacyApiGroupJsonRpcMethods( + final BlockchainQueries blockchainQueries, + final ProtocolSchedule protocolSchedule, + final TransactionPool transactionPool, + final PrivacyParameters privacyParameters, + final JsonRpcMethod rpcMethod) { + super(blockchainQueries, protocolSchedule, transactionPool, privacyParameters); + this.rpcMethod = rpcMethod; + } + + @Override + protected Map create( + final PrivacyController privacyController, + final EnclavePublicKeyProvider enclavePublicKeyProvider) { + this.enclavePublicKeyProvider = enclavePublicKeyProvider; + return mapOf(rpcMethod); + } + + @Override + protected RpcApi getApiGroup() { + return RpcApis.PRIV; + } } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivacyController.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivacyController.java index b6d88343862..4efdf5334c2 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivacyController.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivacyController.java @@ -46,7 +46,6 @@ public class PrivacyController { private static final Logger LOG = LogManager.getLogger(); private final Enclave enclave; - private final String enclavePublicKey; private final PrivateStateStorage privateStateStorage; private final WorldStateArchive privateWorldStateArchive; private final PrivateTransactionValidator privateTransactionValidator; @@ -58,7 +57,6 @@ public PrivacyController( final PrivateMarkerTransactionFactory privateMarkerTransactionFactory) { this( privacyParameters.getEnclave(), - privacyParameters.getEnclavePublicKey(), privacyParameters.getPrivateStateStorage(), privacyParameters.getPrivateWorldStateArchive(), new PrivateTransactionValidator(chainId), @@ -67,23 +65,22 @@ public PrivacyController( public PrivacyController( final Enclave enclave, - final String enclavePublicKey, final PrivateStateStorage privateStateStorage, final WorldStateArchive privateWorldStateArchive, final PrivateTransactionValidator privateTransactionValidator, final PrivateMarkerTransactionFactory privateMarkerTransactionFactory) { this.enclave = enclave; - this.enclavePublicKey = enclavePublicKey; this.privateStateStorage = privateStateStorage; this.privateWorldStateArchive = privateWorldStateArchive; this.privateTransactionValidator = privateTransactionValidator; this.privateMarkerTransactionFactory = privateMarkerTransactionFactory; } - public SendTransactionResponse sendTransaction(final PrivateTransaction privateTransaction) { + public SendTransactionResponse sendTransaction( + final PrivateTransaction privateTransaction, final String enclavePublicKey) { try { LOG.trace("Storing private transaction in enclave"); - final SendResponse sendResponse = sendRequest(privateTransaction); + final SendResponse sendResponse = sendRequest(privateTransaction, enclavePublicKey); final String enclaveKey = sendResponse.getKey(); if (privateTransaction.getPrivacyGroupId().isPresent()) { final String privacyGroupId = privateTransaction.getPrivacyGroupId().get().toBase64String(); @@ -99,20 +96,25 @@ public SendTransactionResponse sendTransaction(final PrivateTransaction privateT } } - public ReceiveResponse retrieveTransaction(final String enclaveKey) { + public ReceiveResponse retrieveTransaction( + final String enclaveKey, final String enclavePublicKey) { return enclave.receive(enclaveKey, enclavePublicKey); } public PrivacyGroup createPrivacyGroup( - final List addresses, final String name, final String description) { + final List addresses, + final String name, + final String description, + final String enclavePublicKey) { return enclave.createPrivacyGroup(addresses, enclavePublicKey, name, description); } - public String deletePrivacyGroup(final String privacyGroupId) { + public String deletePrivacyGroup(final String privacyGroupId, final String enclavePublicKey) { return enclave.deletePrivacyGroup(privacyGroupId, enclavePublicKey); } - public PrivacyGroup[] findPrivacyGroup(final List addresses) { + public PrivacyGroup[] findPrivacyGroup( + final List addresses, final String enclavePublicKey) { return enclave.findPrivacyGroup(addresses); } @@ -122,13 +124,19 @@ public Transaction createPrivacyMarkerTransaction( } public ValidationResult validatePrivateTransaction( - final PrivateTransaction privateTransaction, final String privacyGroupId) { + final PrivateTransaction privateTransaction, + final String privacyGroupId, + final String enclavePublicKey) { return privateTransactionValidator.validate( - privateTransaction, determineNonce(privateTransaction.getSender(), privacyGroupId)); + privateTransaction, + determineNonce(privateTransaction.getSender(), privacyGroupId, enclavePublicKey)); } public long determineNonce( - final String privateFrom, final String[] privateFor, final Address address) { + final String privateFrom, + final String[] privateFor, + final Address address, + final String enclavePublicKey) { final List groupMembers = Lists.asList(privateFrom, privateFor); final List matchingGroups = @@ -150,10 +158,11 @@ public long determineNonce( final String privacyGroupId = legacyGroups.get(0).getPrivacyGroupId(); - return determineNonce(address, privacyGroupId); + return determineNonce(address, privacyGroupId, enclavePublicKey); } - public long determineNonce(final Address sender, final String privacyGroupId) { + public long determineNonce( + final Address sender, final String privacyGroupId, final String enclavePublicKey) { return privateStateStorage .getLatestStateRoot(Bytes.fromBase64String(privacyGroupId)) .map( @@ -177,7 +186,8 @@ public long determineNonce(final Address sender, final String privacyGroupId) { Account.DEFAULT_NONCE); } - private SendResponse sendRequest(final PrivateTransaction privateTransaction) { + private SendResponse sendRequest( + final PrivateTransaction privateTransaction, final String enclavePublicKey) { final BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput(); privateTransaction.writeTo(rlpOutput); final String payload = rlpOutput.encoded().toBase64String(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivacyControllerTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivacyControllerTest.java index a3a0a0edb26..712c678d00e 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivacyControllerTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivacyControllerTest.java @@ -24,6 +24,7 @@ import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; @@ -71,10 +72,12 @@ public class PrivacyControllerTest { new BigInteger( "8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", 16))); private static final byte[] PAYLOAD = new byte[0]; - private static final String PRIVACY_GROUP_ID = "pg_id"; private static final List PRIVACY_GROUP_ADDRESSES = newArrayList("8f2a", "fb23"); private static final String PRIVACY_GROUP_NAME = "pg_name"; private static final String PRIVACY_GROUP_DESCRIPTION = "pg_desc"; + private static final String ENCLAVE_PUBLIC_KEY = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; + private static final String ENCLAVE_KEY2 = "Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs="; + private static final String PRIVACY_GROUP_ID = "DyAOiF/ynpc+JXa2YAGB0bCitSlOMNm+ShmB/7M6C4w="; private PrivacyController privacyController; private PrivacyController brokenPrivacyController; @@ -140,7 +143,6 @@ public void setUp() throws Exception { privacyController = new PrivacyController( enclave, - enclavePublicKey, privateStateStorage, worldStateArchive, privateTransactionValidator, @@ -149,7 +151,6 @@ public void setUp() throws Exception { brokenPrivacyController = new PrivacyController( brokenMockEnclave(), - enclavePublicKey, privateStateStorage, worldStateArchive, privateTransactionValidator, @@ -163,11 +164,11 @@ public void sendsValidLegacyTransaction() { final PrivateTransaction transaction = buildLegacyPrivateTransaction(1); final SendTransactionResponse sendTransactionResponse = - privacyController.sendTransaction(transaction); + privacyController.sendTransaction(transaction, ENCLAVE_PUBLIC_KEY); final ValidationResult validationResult = privacyController.validatePrivateTransaction( - transaction, sendTransactionResponse.getPrivacyGroupId()); + transaction, sendTransactionResponse.getPrivacyGroupId(), ENCLAVE_PUBLIC_KEY); final Transaction markerTransaction = privacyController.createPrivacyMarkerTransaction( @@ -179,6 +180,8 @@ public void sendsValidLegacyTransaction() { assertThat(markerTransaction.getNonce()).isEqualTo(PUBLIC_TRANSACTION.getNonce()); assertThat(markerTransaction.getSender()).isEqualTo(PUBLIC_TRANSACTION.getSender()); assertThat(markerTransaction.getValue()).isEqualTo(PUBLIC_TRANSACTION.getValue()); + verify(enclave) + .send(anyString(), eq(ENCLAVE_PUBLIC_KEY), eq(List.of(ENCLAVE_PUBLIC_KEY, ENCLAVE_KEY2))); } @Test @@ -187,11 +190,11 @@ public void sendValidBesuTransaction() { final PrivateTransaction transaction = buildBesuPrivateTransaction(1); final SendTransactionResponse sendTransactionResponse = - privacyController.sendTransaction(transaction); + privacyController.sendTransaction(transaction, ENCLAVE_PUBLIC_KEY); final ValidationResult validationResult = privacyController.validatePrivateTransaction( - transaction, transaction.getPrivacyGroupId().get().toString()); + transaction, transaction.getPrivacyGroupId().get().toString(), ENCLAVE_PUBLIC_KEY); final Transaction markerTransaction = privacyController.createPrivacyMarkerTransaction( @@ -203,12 +206,16 @@ public void sendValidBesuTransaction() { assertThat(markerTransaction.getNonce()).isEqualTo(PUBLIC_TRANSACTION.getNonce()); assertThat(markerTransaction.getSender()).isEqualTo(PUBLIC_TRANSACTION.getSender()); assertThat(markerTransaction.getValue()).isEqualTo(PUBLIC_TRANSACTION.getValue()); + verify(enclave).send(anyString(), eq(ENCLAVE_PUBLIC_KEY), eq(PRIVACY_GROUP_ID)); } @Test public void sendTransactionWhenEnclaveFailsThrowsEnclaveError() { assertThatExceptionOfType(EnclaveServerException.class) - .isThrownBy(() -> brokenPrivacyController.sendTransaction(buildLegacyPrivateTransaction())); + .isThrownBy( + () -> + brokenPrivacyController.sendTransaction( + buildLegacyPrivateTransaction(), ENCLAVE_PUBLIC_KEY)); } @Test @@ -218,10 +225,10 @@ public void validateTransactionWithTooLowNonceReturnsError() { final PrivateTransaction transaction = buildLegacyPrivateTransaction(0); final SendTransactionResponse sendTransactionResponse = - privacyController.sendTransaction(transaction); + privacyController.sendTransaction(transaction, ENCLAVE_PUBLIC_KEY); final ValidationResult validationResult = privacyController.validatePrivateTransaction( - transaction, sendTransactionResponse.getPrivacyGroupId()); + transaction, sendTransactionResponse.getPrivacyGroupId(), ENCLAVE_PUBLIC_KEY); assertThat(validationResult).isEqualTo(ValidationResult.invalid(PRIVATE_NONCE_TOO_LOW)); } @@ -233,10 +240,10 @@ public void validateTransactionWithIncorrectNonceReturnsError() { final PrivateTransaction transaction = buildLegacyPrivateTransaction(2); final SendTransactionResponse sendTransactionResponse = - privacyController.sendTransaction(transaction); + privacyController.sendTransaction(transaction, ENCLAVE_PUBLIC_KEY); final ValidationResult validationResult = privacyController.validatePrivateTransaction( - transaction, sendTransactionResponse.getPrivacyGroupId()); + transaction, sendTransactionResponse.getPrivacyGroupId(), ENCLAVE_PUBLIC_KEY); assertThat(validationResult).isEqualTo(ValidationResult.invalid(INCORRECT_PRIVATE_NONCE)); } @@ -245,7 +252,8 @@ public void retrievesTransaction() { when(enclave.receive(anyString(), anyString())) .thenReturn(new ReceiveResponse(PAYLOAD, PRIVACY_GROUP_ID)); - final ReceiveResponse receiveResponse = privacyController.retrieveTransaction(TRANSACTION_KEY); + final ReceiveResponse receiveResponse = + privacyController.retrieveTransaction(TRANSACTION_KEY, ENCLAVE_PUBLIC_KEY); assertThat(receiveResponse.getPayload()).isEqualTo(PAYLOAD); assertThat(receiveResponse.getPrivacyGroupId()).isEqualTo(PRIVACY_GROUP_ID); @@ -266,7 +274,10 @@ public void createsPrivacyGroup() { final PrivacyGroup privacyGroup = privacyController.createPrivacyGroup( - PRIVACY_GROUP_ADDRESSES, PRIVACY_GROUP_NAME, PRIVACY_GROUP_DESCRIPTION); + PRIVACY_GROUP_ADDRESSES, + PRIVACY_GROUP_NAME, + PRIVACY_GROUP_DESCRIPTION, + ENCLAVE_PUBLIC_KEY); assertThat(privacyGroup).isEqualToComparingFieldByField(enclavePrivacyGroupResponse); verify(enclave) @@ -281,7 +292,8 @@ public void createsPrivacyGroup() { public void deletesPrivacyGroup() { when(enclave.deletePrivacyGroup(anyString(), anyString())).thenReturn(PRIVACY_GROUP_ID); - final String deletedPrivacyGroupId = privacyController.deletePrivacyGroup(PRIVACY_GROUP_ID); + final String deletedPrivacyGroupId = + privacyController.deletePrivacyGroup(PRIVACY_GROUP_ID, ENCLAVE_PUBLIC_KEY); assertThat(deletedPrivacyGroupId).isEqualTo(PRIVACY_GROUP_ID); verify(enclave).deletePrivacyGroup(PRIVACY_GROUP_ID, enclavePublicKey); @@ -299,7 +311,7 @@ public void findsPrivacyGroup() { when(enclave.findPrivacyGroup(any())).thenReturn(new PrivacyGroup[] {privacyGroup}); final PrivacyGroup[] privacyGroups = - privacyController.findPrivacyGroup(PRIVACY_GROUP_ADDRESSES); + privacyController.findPrivacyGroup(PRIVACY_GROUP_ADDRESSES, ENCLAVE_PUBLIC_KEY); assertThat(privacyGroups).hasSize(1); assertThat(privacyGroups[0]).isEqualToComparingFieldByField(privacyGroup); verify(enclave).findPrivacyGroup(PRIVACY_GROUP_ADDRESSES); @@ -318,7 +330,8 @@ public void determinesNonceForEeaRequest() { when(account.getNonce()).thenReturn(8L); final long nonce = - privacyController.determineNonce("privateFrom", new String[] {"first", "second"}, address); + privacyController.determineNonce( + "privateFrom", new String[] {"first", "second"}, address, ENCLAVE_PUBLIC_KEY); assertThat(nonce).isEqualTo(reportedNonce); verify(enclave) @@ -335,7 +348,8 @@ public void determineNonceForEeaRequestWithNoMatchingGroupReturnsZero() { when(enclave.findPrivacyGroup(any())).thenReturn(returnedGroups); final long nonce = - privacyController.determineNonce("privateFrom", new String[] {"first", "second"}, address); + privacyController.determineNonce( + "privateFrom", new String[] {"first", "second"}, address, ENCLAVE_PUBLIC_KEY); assertThat(nonce).isEqualTo(reportedNonce); verify(enclave) @@ -358,7 +372,7 @@ public void determineNonceForEeaRequestWithMoreThanOneMatchingGroupThrowsExcepti .isThrownBy( () -> privacyController.determineNonce( - "privateFrom", new String[] {"first", "second"}, address)); + "privateFrom", new String[] {"first", "second"}, address, ENCLAVE_PUBLIC_KEY)); } @Test @@ -367,7 +381,7 @@ public void determineNonceForPrivacyGroupRequestWhenAccountExists() { when(account.getNonce()).thenReturn(4L); - final long nonce = privacyController.determineNonce(address, "Group1"); + final long nonce = privacyController.determineNonce(address, "Group1", ENCLAVE_PUBLIC_KEY); assertThat(nonce).isEqualTo(4L); verify(privateStateStorage).getLatestStateRoot(Base64.decode("Group1")); @@ -382,7 +396,7 @@ public void determineNonceForPrivacyGroupRequestWhenPrivateStateDoesNotExist() { when(privateStateStorage.getLatestStateRoot(Base64.decode("Group1"))) .thenReturn(Optional.empty()); - final long nonce = privacyController.determineNonce(address, "Group1"); + final long nonce = privacyController.determineNonce(address, "Group1", ENCLAVE_PUBLIC_KEY); assertThat(nonce).isEqualTo(Account.DEFAULT_NONCE); verifyNoInteractions(worldStateArchive, mutableWorldState, account); @@ -396,7 +410,7 @@ public void determineNonceForPrivacyGroupRequestWhenWorldStateDoesNotExist() { .thenReturn(Optional.of(hash)); when(worldStateArchive.getMutable(hash)).thenReturn(Optional.empty()); - final long nonce = privacyController.determineNonce(address, "Group1"); + final long nonce = privacyController.determineNonce(address, "Group1", ENCLAVE_PUBLIC_KEY); assertThat(nonce).isEqualTo(Account.DEFAULT_NONCE); verifyNoInteractions(mutableWorldState, account); @@ -411,7 +425,7 @@ public void determineNonceForPrivacyGroupRequestWhenAccountDoesNotExist() { when(worldStateArchive.getMutable(hash)).thenReturn(Optional.of(mutableWorldState)); when(mutableWorldState.get(address)).thenReturn(null); - final long nonce = privacyController.determineNonce(address, "Group1"); + final long nonce = privacyController.determineNonce(address, "Group1", ENCLAVE_PUBLIC_KEY); assertThat(nonce).isEqualTo(Account.DEFAULT_NONCE); verifyNoInteractions(account); @@ -423,19 +437,16 @@ private static PrivateTransaction buildLegacyPrivateTransaction() { private static PrivateTransaction buildLegacyPrivateTransaction(final long nonce) { return buildPrivateTransaction(nonce) - .privateFrom(Base64.decode("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=")) - .privateFor( - newArrayList( - Base64.decode("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="), - Base64.decode("Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs="))) + .privateFrom(Base64.decode(ENCLAVE_PUBLIC_KEY)) + .privateFor(newArrayList(Base64.decode(ENCLAVE_PUBLIC_KEY), Base64.decode(ENCLAVE_KEY2))) .signAndBuild(KEY_PAIR); } private static PrivateTransaction buildBesuPrivateTransaction(final long nonce) { return buildPrivateTransaction(nonce) - .privateFrom(Base64.decode("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=")) - .privacyGroupId(Base64.decode("DyAOiF/ynpc+JXa2YAGB0bCitSlOMNm+ShmB/7M6C4w=")) + .privateFrom(Base64.decode(ENCLAVE_PUBLIC_KEY)) + .privacyGroupId(Base64.decode(PRIVACY_GROUP_ID)) .signAndBuild(KEY_PAIR); }