From af1ca586c13c5451813f96c291425bdb9efdc6b5 Mon Sep 17 00:00:00 2001 From: Puneetha Karamsetty Date: Mon, 15 Jul 2019 03:34:42 +0100 Subject: [PATCH] Add eea_findPrivacyGroup endpoint in Pantheon (#1635) Signed-off-by: Adrian Sutton --- .../pegasys/pantheon/enclave/EnclaveTest.java | 52 ++++++++++++-- .../pegasys/pantheon/enclave/Enclave.java | 8 +++ .../types/FindPrivacyGroupRequest.java | 31 +++++++++ .../types/FindPrivacyGroupResponse.java | 60 +++++++++++++++++ .../jsonrpc/JsonRpcEnclaveErrorConverter.java | 45 ++++--------- .../jsonrpc/JsonRpcMethodsFactory.java | 2 + .../pantheon/ethereum/jsonrpc/RpcMethod.java | 1 + .../methods/privacy/EeaFindPrivacyGroup.java | 67 +++++++++++++++++++ .../internal/response/JsonRpcError.java | 11 ++- 9 files changed, 237 insertions(+), 40 deletions(-) create mode 100644 enclave/src/main/java/tech/pegasys/pantheon/enclave/types/FindPrivacyGroupRequest.java create mode 100644 enclave/src/main/java/tech/pegasys/pantheon/enclave/types/FindPrivacyGroupResponse.java create mode 100644 ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/EeaFindPrivacyGroup.java diff --git a/enclave/src/integration-test/java/tech/pegasys/pantheon/enclave/EnclaveTest.java b/enclave/src/integration-test/java/tech/pegasys/pantheon/enclave/EnclaveTest.java index c465d4a904..bc0e68626f 100644 --- a/enclave/src/integration-test/java/tech/pegasys/pantheon/enclave/EnclaveTest.java +++ b/enclave/src/integration-test/java/tech/pegasys/pantheon/enclave/EnclaveTest.java @@ -21,6 +21,8 @@ import tech.pegasys.orion.testutil.OrionTestHarness; import tech.pegasys.orion.testutil.OrionTestHarnessFactory; import tech.pegasys.pantheon.enclave.types.CreatePrivacyGroupRequest; import tech.pegasys.pantheon.enclave.types.DeletePrivacyGroupRequest; +import tech.pegasys.pantheon.enclave.types.FindPrivacyGroupRequest; +import tech.pegasys.pantheon.enclave.types.FindPrivacyGroupResponse; import tech.pegasys.pantheon.enclave.types.PrivacyGroup; import tech.pegasys.pantheon.enclave.types.ReceiveRequest; import tech.pegasys.pantheon.enclave.types.ReceiveResponse; @@ -33,8 +35,8 @@ import java.net.URI; import java.util.List; import com.google.common.collect.Lists; -import org.junit.AfterClass; -import org.junit.BeforeClass; +import org.junit.After; +import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -48,8 +50,8 @@ public class EnclaveTest { private static OrionTestHarness testHarness; - @BeforeClass - public static void setUpOnce() throws Exception { + @Before + public void setUpOnce() throws Exception { folder.create(); testHarness = @@ -59,8 +61,8 @@ public class EnclaveTest { enclave = new Enclave(testHarness.clientUrl()); } - @AfterClass - public static void tearDownOnce() { + @After + public void tearDownOnce() { testHarness.getOrion().stop(); } @@ -126,6 +128,44 @@ public class EnclaveTest { assertThat(privacyGroupResponse.getPrivacyGroupId()).isEqualTo(response); } + @Test + public void testCreateFindDeleteFindPrivacyGroup() throws Exception { + List publicKeys = testHarness.getPublicKeys(); + String name = "name"; + String description = "desc"; + CreatePrivacyGroupRequest privacyGroupRequest = + new CreatePrivacyGroupRequest( + publicKeys.toArray(new String[0]), publicKeys.get(0), name, description); + + PrivacyGroup privacyGroupResponse = enclave.createPrivacyGroup(privacyGroupRequest); + + assertThat(privacyGroupResponse.getPrivacyGroupId()).isNotNull(); + assertThat(privacyGroupResponse.getName()).isEqualTo(name); + assertThat(privacyGroupResponse.getDescription()).isEqualTo(description); + assertThat(privacyGroupResponse.getType()).isEqualTo(PrivacyGroup.Type.PANTHEON); + + FindPrivacyGroupRequest findPrivacyGroupRequest = + new FindPrivacyGroupRequest(publicKeys.toArray(new String[0])); + FindPrivacyGroupResponse[] findPrivacyGroupResponse = + enclave.findPrivacyGroup(findPrivacyGroupRequest); + + assertThat(findPrivacyGroupResponse.length).isEqualTo(1); + assertThat(findPrivacyGroupResponse[0].privacyGroupId()) + .isEqualTo(privacyGroupResponse.getPrivacyGroupId()); + + DeletePrivacyGroupRequest deletePrivacyGroupRequest = + new DeletePrivacyGroupRequest(privacyGroupResponse.getPrivacyGroupId(), publicKeys.get(0)); + + String response = enclave.deletePrivacyGroup(deletePrivacyGroupRequest); + + assertThat(privacyGroupResponse.getPrivacyGroupId()).isEqualTo(response); + + findPrivacyGroupRequest = new FindPrivacyGroupRequest(publicKeys.toArray(new String[0])); + findPrivacyGroupResponse = enclave.findPrivacyGroup(findPrivacyGroupRequest); + + assertThat(findPrivacyGroupResponse.length).isEqualTo(0); + } + @Test public void whenUpCheckFailsThrows() { final Throwable thrown = catchThrowable(() -> new Enclave(URI.create("http://null")).upCheck()); diff --git a/enclave/src/main/java/tech/pegasys/pantheon/enclave/Enclave.java b/enclave/src/main/java/tech/pegasys/pantheon/enclave/Enclave.java index 3b9592a11f..a9fab344db 100644 --- a/enclave/src/main/java/tech/pegasys/pantheon/enclave/Enclave.java +++ b/enclave/src/main/java/tech/pegasys/pantheon/enclave/Enclave.java @@ -15,6 +15,8 @@ package tech.pegasys.pantheon.enclave; import tech.pegasys.pantheon.enclave.types.CreatePrivacyGroupRequest; import tech.pegasys.pantheon.enclave.types.DeletePrivacyGroupRequest; import tech.pegasys.pantheon.enclave.types.ErrorResponse; +import tech.pegasys.pantheon.enclave.types.FindPrivacyGroupRequest; +import tech.pegasys.pantheon.enclave.types.FindPrivacyGroupResponse; import tech.pegasys.pantheon.enclave.types.PrivacyGroup; import tech.pegasys.pantheon.enclave.types.ReceiveRequest; import tech.pegasys.pantheon.enclave.types.ReceiveResponse; @@ -75,6 +77,12 @@ public class Enclave { return executePost(buildPostRequest(JSON, content, "/deletePrivacyGroup"), String.class); } + public FindPrivacyGroupResponse[] findPrivacyGroup(final FindPrivacyGroupRequest content) + throws Exception { + Request request = buildPostRequest(JSON, content, "/findPrivacyGroup"); + return executePost(request, FindPrivacyGroupResponse[].class); + } + private Request buildPostRequest( final MediaType mediaType, final Object content, final String endpoint) throws Exception { final RequestBody body = diff --git a/enclave/src/main/java/tech/pegasys/pantheon/enclave/types/FindPrivacyGroupRequest.java b/enclave/src/main/java/tech/pegasys/pantheon/enclave/types/FindPrivacyGroupRequest.java new file mode 100644 index 0000000000..eeef111696 --- /dev/null +++ b/enclave/src/main/java/tech/pegasys/pantheon/enclave/types/FindPrivacyGroupRequest.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package tech.pegasys.pantheon.enclave.types; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class FindPrivacyGroupRequest { + + private final String[] addresses; + + @JsonCreator + public FindPrivacyGroupRequest(@JsonProperty("addresses") final String[] addresses) { + this.addresses = addresses; + } + + @JsonProperty("addresses") + public String[] addresses() { + return addresses; + } +} diff --git a/enclave/src/main/java/tech/pegasys/pantheon/enclave/types/FindPrivacyGroupResponse.java b/enclave/src/main/java/tech/pegasys/pantheon/enclave/types/FindPrivacyGroupResponse.java new file mode 100644 index 0000000000..e1ced51416 --- /dev/null +++ b/enclave/src/main/java/tech/pegasys/pantheon/enclave/types/FindPrivacyGroupResponse.java @@ -0,0 +1,60 @@ +/* + * Copyright 2019 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package tech.pegasys.pantheon.enclave.types; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class FindPrivacyGroupResponse implements Serializable { + + private String privacyGroupId; + private String name; + private String description; + private String[] members; + + @JsonCreator + public FindPrivacyGroupResponse( + @JsonProperty("privacyGroupId") final String privacyGroupId, + @JsonProperty("name") final String name, + @JsonProperty("description") final String description, + @JsonProperty("members") final String[] members) { + this.privacyGroupId = privacyGroupId; + this.name = name; + this.description = description; + this.members = members; + } + + @JsonProperty("privacyGroupId") + public String privacyGroupId() { + return privacyGroupId; + } + + @JsonProperty("name") + public String name() { + return name; + } + + @JsonProperty("description") + public String description() { + return description; + } + + @JsonProperty("members") + public String[] members() { + return members; + } + + public FindPrivacyGroupResponse() {} +} diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcEnclaveErrorConverter.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcEnclaveErrorConverter.java index 0a340a9f3d..40a5f4a4e6 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcEnclaveErrorConverter.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcEnclaveErrorConverter.java @@ -14,44 +14,23 @@ package tech.pegasys.pantheon.ethereum.jsonrpc; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcError; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + public class JsonRpcEnclaveErrorConverter { public static JsonRpcError convertEnclaveInvalidReason(final String reason) { - switch (reason) { - case "NodeMissingPeerUrl": - return JsonRpcError.NODE_MISSING_PEER_URL; - case "NodePushingToPeer": - return JsonRpcError.NODE_PUSHING_TO_PEER; - case "NodePropagatingToAllPeers": - return JsonRpcError.NODE_PROPAGATING_TO_ALL_PEERS; - case "NoSenderKey": - return JsonRpcError.NO_SENDER_KEY; - case "InvalidPayload": - return JsonRpcError.INVALID_PAYLOAD; - case "EnclaveCreateKeyPair": - return JsonRpcError.ENCLAVE_CREATE_KEY_PAIR; - case "EnclaveDecodePublicKey": - return JsonRpcError.ENCLAVE_DECODE_PUBLIC_KEY; - case "EnclaveDecryptWrongPrivateKey": - return JsonRpcError.ENCLAVE_DECRYPT_WRONG_PRIVATE_KEY; - case "EnclaveEncryptCombineKeys": - return JsonRpcError.ENCLAVE_ENCRYPT_COMBINE_KEYS; - case "EnclaveMissingPrivateKeyPasswords": - return JsonRpcError.ENCLAVE_MISSING_PRIVATE_KEY_PASSWORD; - case "EnclaveNoMatchingPrivateKey": - return JsonRpcError.ENCLAVE_NO_MATCHING_PRIVATE_KEY; - case "EnclaveNotPayloadOwner": - return JsonRpcError.ENCLAVE_NOT_PAYLOAD_OWNER; - case "EnclaveUnsupportedPrivateKeyType": - return JsonRpcError.ENCLAVE_UNSUPPORTED_PRIVATE_KEY_TYPE; - case "EnclaveStorageDecrypt": - return JsonRpcError.ENCLAVE_STORAGE_DECRYPT; - case "EnclavePrivacyGroupIdCreation": - return JsonRpcError.ENCLAVE_PRIVACY_GROUP_CREATION; + List err = + Arrays.stream(JsonRpcError.values()) + .filter(e -> e.getMessage().contains(reason)) + .collect(Collectors.toList()); - default: - return JsonRpcError.ENCLAVE_ERROR; + if (err.size() == 1) { + return err.get(0); + } else { + return JsonRpcError.ENCLAVE_ERROR; } } } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java index 3e8a3ffce1..20acae4ae8 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java @@ -92,6 +92,7 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.permissioning.Per import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.permissioning.PermRemoveNodesFromWhitelist; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.privacy.EeaCreatePrivacyGroup; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.privacy.EeaDeletePrivacyGroup; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.privacy.EeaFindPrivacyGroup; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.privacy.EeaGetPrivacyPrecompileAddress; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.privacy.EeaGetPrivateTransaction; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.privacy.EeaGetTransactionCount; @@ -333,6 +334,7 @@ public class JsonRpcMethodsFactory { new EeaGetPrivateTransaction(enclave, parameter, privacyParameters), new EeaCreatePrivacyGroup(new Enclave(privacyParameters.getEnclaveUri()), parameter), new EeaDeletePrivacyGroup(new Enclave(privacyParameters.getEnclaveUri()), parameter), + new EeaFindPrivacyGroup(new Enclave(privacyParameters.getEnclaveUri()), parameter), new EeaGetPrivacyPrecompileAddress(privacyParameters)); } return enabledMethods; diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/RpcMethod.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/RpcMethod.java index 9ccb95f8f7..fc1b7ef597 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/RpcMethod.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/RpcMethod.java @@ -38,6 +38,7 @@ public enum RpcMethod { EEA_GET_TRANSACTION_RECEIPT("eea_getTransactionReceipt"), EEA_CREATE_PRIVACY_GROUP("eea_createPrivacyGroup"), EEA_DELETE_PRIVACY_GROUP("eea_deletePrivacyGroup"), + EEA_FIND_PRIVACY_GROUP("eea_findPrivacyGroup"), EEA_SEND_RAW_TRANSACTION("eea_sendRawTransaction"), ETH_ACCOUNTS("eth_accounts"), ETH_BLOCK_NUMBER("eth_blockNumber"), diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/EeaFindPrivacyGroup.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/EeaFindPrivacyGroup.java new file mode 100644 index 0000000000..ccd1c9b417 --- /dev/null +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/EeaFindPrivacyGroup.java @@ -0,0 +1,67 @@ +/* + * Copyright 2019 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.privacy; + +import static org.apache.logging.log4j.LogManager.getLogger; + +import tech.pegasys.pantheon.enclave.Enclave; +import tech.pegasys.pantheon.enclave.types.FindPrivacyGroupRequest; +import tech.pegasys.pantheon.enclave.types.FindPrivacyGroupResponse; +import tech.pegasys.pantheon.ethereum.jsonrpc.RpcMethod; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.JsonRpcMethod; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcError; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; + +import java.util.Arrays; + +import org.apache.logging.log4j.Logger; + +public class EeaFindPrivacyGroup implements JsonRpcMethod { + + private static final Logger LOG = getLogger(); + private final Enclave enclave; + private final JsonRpcParameter parameters; + + public EeaFindPrivacyGroup(final Enclave enclave, final JsonRpcParameter parameters) { + this.enclave = enclave; + this.parameters = parameters; + } + + @Override + public String getName() { + return RpcMethod.EEA_FIND_PRIVACY_GROUP.getMethodName(); + } + + @Override + public JsonRpcResponse response(final JsonRpcRequest request) { + LOG.trace("Executing {}", RpcMethod.EEA_FIND_PRIVACY_GROUP.getMethodName()); + + final String[] addresses = parameters.required(request.getParams(), 0, String[].class); + + LOG.trace("Finding a privacy group with members {}", Arrays.toString(addresses)); + + FindPrivacyGroupRequest findPrivacyGroupRequest = new FindPrivacyGroupRequest(addresses); + FindPrivacyGroupResponse[] response; + try { + response = enclave.findPrivacyGroup(findPrivacyGroupRequest); + } catch (Exception e) { + LOG.error("Failed to fetch group from Enclave with error " + e.getMessage()); + LOG.error(e); + return new JsonRpcSuccessResponse(request.getId(), JsonRpcError.FIND_PRIVACY_GROUP_ERROR); + } + return new JsonRpcSuccessResponse(request.getId(), response); + } +} diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/response/JsonRpcError.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/response/JsonRpcError.java index fc7adfe0c7..138b8aa139 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/response/JsonRpcError.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/response/JsonRpcError.java @@ -105,6 +105,7 @@ public enum JsonRpcError { PRIVACY_NOT_ENABLED(-50100, "Privacy is not enabled to get the precompiled address"), CREATE_PRIVACY_GROUP_ERROR(-50100, "Error creating privacy group"), DELETE_PRIVACY_GROUP_ERROR(-50100, "Error deleting privacy group"), + FIND_PRIVACY_GROUP_ERROR(-50100, "Error finding privacy group"), VALUE_NOT_ZERO(-50100, "We cannot transfer ether in private transaction yet."), DECODE_ERROR(-50100, "Unable to decode the private signed raw transaction"), @@ -131,7 +132,15 @@ public enum JsonRpcError { ENCLAVE_UNSUPPORTED_PRIVATE_KEY_TYPE(-50200, "EnclaveUnsupportedPrivateKeyType"), ENCLAVE_STORAGE_DECRYPT(-50200, "EnclaveStorageDecrypt"), ENCLAVE_PRIVACY_GROUP_CREATION(-50200, "EnclavePrivacyGroupIdCreation"), - CREATE_GROUP_INCLUDE_SELF(-50200, "CreatePrivacyGroupShouldIncludeSelf"); + CREATE_GROUP_INCLUDE_SELF(-50200, "CreatePrivacyGroupShouldIncludeSelf"), + + /** Storing privacy group issue */ + ENCLAVE_UNABLE_STORE_PRIVACY_GROUP(-50200, "PrivacyGroupNotStored"), + ENCLAVE_UNABLE_DELETE_PRIVACY_GROUP(-50200, "PrivacyGroupNotDeleted"), + ENCLAVE_UNABLE_PUSH_DELETE_PRIVACY_GROUP(-50200, "PrivacyGroupNotPushed"), + ENCLAVE_PRIVACY_GROUP_MISSING(-50200, "PrivacyGroupNotFound"), + ENCLAVE_PRIVACY_QUERY_ERROR(-50200, "PrivacyGroupQueryError"), + METHOD_UNIMPLEMENTED(-50200, "MethodUnimplemented"); private final int code; private final String message;