Privacy rpcs to go through privacy controller instead directly through Enclave (#243)

Signed-off-by: Jason Frame <jasonwframe@gmail.com>
pull/269/head
Jason Frame 5 years ago committed by GitHub
parent 756d097b8e
commit a0e87148e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/PrivacyNode.java
  2. 11
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/PrivacyClusterAcceptanceTest.java
  3. 58
      enclave/src/integration-test/java/org/hyperledger/besu/enclave/EnclaveTest.java
  4. 54
      enclave/src/main/java/org/hyperledger/besu/enclave/Enclave.java
  5. 8
      enclave/src/main/java/org/hyperledger/besu/enclave/types/CreatePrivacyGroupRequest.java
  6. 8
      enclave/src/main/java/org/hyperledger/besu/enclave/types/FindPrivacyGroupRequest.java
  7. 9
      enclave/src/main/java/org/hyperledger/besu/enclave/types/PrivacyGroup.java
  8. 22
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivGetPrivateTransactionIntegrationTest.java
  9. 26
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/DisabledPrivacyRpcMethod.java
  10. 37
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/PrivacySendTransaction.java
  11. 49
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransaction.java
  12. 26
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCreatePrivacyGroup.java
  13. 30
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDeletePrivacyGroup.java
  14. 45
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransaction.java
  15. 25
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivFindPrivacyGroup.java
  16. 17
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetEeaTransactionCount.java
  17. 6
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivacyPrecompileAddress.java
  18. 40
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransaction.java
  19. 19
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionCount.java
  20. 36
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceipt.java
  21. 69
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivateEeaNonceProvider.java
  22. 8
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/parameters/CreatePrivacyGroupParameter.java
  23. 14
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EeaJsonRpcMethods.java
  24. 21
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivJsonRpcMethods.java
  25. 23
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivacyApiGroupJsonRpcMethods.java
  26. 34
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/privacy/eea/PrivGetEeaTransactionCountTest.java
  27. 113
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/privacy/eea/PrivateEeaNonceProviderTest.java
  28. 102
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransactionTest.java
  29. 61
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCreatePrivacyGroupTest.java
  30. 58
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDeletePrivacyGroupTest.java
  31. 49
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransactionTest.java
  32. 57
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivFindPrivacyGroupTest.java
  33. 24
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivacyPrecompileAddressTest.java
  34. 38
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetPrivateTransactionTest.java
  35. 26
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionCountTest.java
  36. 54
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivGetTransactionReceiptTest.java
  37. 89
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivacyApiGroupJsonRpcMethodsTest.java
  38. 18
      ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractIntegrationTest.java
  39. 5
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContract.java
  40. 142
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivacyController.java
  41. 33
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/SendTransactionResponse.java
  42. 5
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractTest.java
  43. 454
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivacyControllerTest.java
  44. 255
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionHandlerTest.java

@ -20,8 +20,6 @@ import org.hyperledger.besu.controller.KeyPairUtil;
import org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.enclave.EnclaveException;
import org.hyperledger.besu.enclave.EnclaveFactory;
import org.hyperledger.besu.enclave.types.SendRequest;
import org.hyperledger.besu.enclave.types.SendRequestLegacy;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.privacy.storage.PrivacyStorageProvider;
@ -109,19 +107,17 @@ public class PrivacyNode implements AutoCloseable {
Arrays.toString(otherNodes.stream().map(node -> node.orion.nodeUrl()).toArray())));
final EnclaveFactory factory = new EnclaveFactory(vertx);
final Enclave enclaveClient = factory.createVertxEnclave(orion.clientUrl());
final SendRequest sendRequest =
new SendRequestLegacy(
"SGVsbG8sIFdvcmxkIQ==",
orion.getDefaultPublicKey(),
otherNodes.stream()
.map(node -> node.orion.getDefaultPublicKey())
.collect(Collectors.toList()));
final String payload = "SGVsbG8sIFdvcmxkIQ==";
final List<String> to =
otherNodes.stream()
.map(node -> node.orion.getDefaultPublicKey())
.collect(Collectors.toList());
Awaitility.await()
.until(
() -> {
try {
enclaveClient.send(sendRequest);
enclaveClient.send(payload, orion.getDefaultPublicKey(), to);
return true;
} catch (final EnclaveException e) {
LOG.info("Waiting for enclave connectivity");

@ -18,7 +18,6 @@ import static org.assertj.core.api.Assertions.assertThat;
import org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.enclave.EnclaveFactory;
import org.hyperledger.besu.enclave.types.ReceiveRequest;
import org.hyperledger.besu.enclave.types.ReceiveResponse;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyAcceptanceTestBase;
@ -161,16 +160,14 @@ public class PrivacyClusterAcceptanceTest extends PrivacyAcceptanceTestBase {
final Enclave aliceEnclave = enclaveFactory.createVertxEnclave(alice.getOrion().clientUrl());
final ReceiveResponse aliceRR =
aliceEnclave.receive(
new ReceiveRequest(
BytesValues.asBase64String(BytesValue.fromHexString(transactionKey)),
alice.getEnclaveKey()));
BytesValues.asBase64String(BytesValue.fromHexString(transactionKey)),
alice.getEnclaveKey());
final Enclave bobEnclave = enclaveFactory.createVertxEnclave(bob.getOrion().clientUrl());
final ReceiveResponse bobRR =
bobEnclave.receive(
new ReceiveRequest(
BytesValues.asBase64String(BytesValue.fromHexString(transactionKey)),
bob.getEnclaveKey()));
BytesValues.asBase64String(BytesValue.fromHexString(transactionKey)),
bob.getEnclaveKey());
assertThat(bobRR).isEqualToComparingFieldByField(aliceRR);

@ -18,14 +18,8 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import org.hyperledger.besu.enclave.types.CreatePrivacyGroupRequest;
import org.hyperledger.besu.enclave.types.DeletePrivacyGroupRequest;
import org.hyperledger.besu.enclave.types.FindPrivacyGroupRequest;
import org.hyperledger.besu.enclave.types.PrivacyGroup;
import org.hyperledger.besu.enclave.types.ReceiveRequest;
import org.hyperledger.besu.enclave.types.ReceiveResponse;
import org.hyperledger.besu.enclave.types.SendRequestBesu;
import org.hyperledger.besu.enclave.types.SendRequestLegacy;
import org.hyperledger.besu.enclave.types.SendResponse;
import org.hyperledger.orion.testutil.OrionKeyConfiguration;
import org.hyperledger.orion.testutil.OrionTestHarness;
@ -84,8 +78,7 @@ public class EnclaveTest {
public void testReceiveThrowsWhenPayloadDoesNotExist() {
final String publicKey = testHarness.getDefaultPublicKey();
final Throwable t =
catchThrowable(() -> enclave.receive(new ReceiveRequest(MOCK_KEY, publicKey)));
final Throwable t = catchThrowable(() -> enclave.receive(MOCK_KEY, publicKey));
assertThat(t.getMessage()).isEqualTo("EnclavePayloadNotFound");
}
@ -95,10 +88,9 @@ public class EnclaveTest {
final List<String> publicKeys = testHarness.getPublicKeys();
final SendResponse sr =
enclave.send(
new SendRequestLegacy(
PAYLOAD, publicKeys.get(0), Lists.newArrayList(publicKeys.get(0))));
final ReceiveResponse rr = enclave.receive(new ReceiveRequest(sr.getKey(), publicKeys.get(0)));
enclave.send(PAYLOAD, publicKeys.get(0), Lists.newArrayList(publicKeys.get(0)));
final ReceiveResponse rr = enclave.receive(sr.getKey(), publicKeys.get(0));
assertThat(rr).isNotNull();
assertThat(new String(rr.getPayload(), UTF_8)).isEqualTo(PAYLOAD);
assertThat(rr.getPrivacyGroupId()).isNotNull();
@ -108,16 +100,13 @@ public class EnclaveTest {
public void testSendWithPrivacyGroupAndReceive() {
final List<String> publicKeys = testHarness.getPublicKeys();
final CreatePrivacyGroupRequest privacyGroupRequest =
new CreatePrivacyGroupRequest(publicKeys.toArray(new String[0]), publicKeys.get(0), "", "");
final PrivacyGroup privacyGroupResponse = enclave.createPrivacyGroup(privacyGroupRequest);
final PrivacyGroup privacyGroupResponse =
enclave.createPrivacyGroup(publicKeys, publicKeys.get(0), "", "");
final SendResponse sr =
enclave.send(
new SendRequestBesu(
PAYLOAD, publicKeys.get(0), privacyGroupResponse.getPrivacyGroupId()));
final ReceiveResponse rr = enclave.receive(new ReceiveRequest(sr.getKey(), publicKeys.get(0)));
enclave.send(PAYLOAD, publicKeys.get(0), privacyGroupResponse.getPrivacyGroupId());
final ReceiveResponse rr = enclave.receive(sr.getKey(), publicKeys.get(0));
assertThat(rr).isNotNull();
assertThat(new String(rr.getPayload(), UTF_8)).isEqualTo(PAYLOAD);
assertThat(rr.getPrivacyGroupId()).isNotNull();
@ -128,11 +117,9 @@ public class EnclaveTest {
final List<String> publicKeys = testHarness.getPublicKeys();
final String name = "testName";
final String description = "testDesc";
final CreatePrivacyGroupRequest privacyGroupRequest =
new CreatePrivacyGroupRequest(
publicKeys.toArray(new String[0]), publicKeys.get(0), name, description);
final PrivacyGroup privacyGroupResponse = enclave.createPrivacyGroup(privacyGroupRequest);
final PrivacyGroup privacyGroupResponse =
enclave.createPrivacyGroup(publicKeys, publicKeys.get(0), name, description);
assertThat(privacyGroupResponse.getPrivacyGroupId()).isNotNull();
assertThat(privacyGroupResponse.getName()).isEqualTo(name);
@ -140,9 +127,7 @@ public class EnclaveTest {
assertThat(privacyGroupResponse.getType()).isEqualByComparingTo(PrivacyGroup.Type.PANTHEON);
final String response =
enclave.deletePrivacyGroup(
new DeletePrivacyGroupRequest(
privacyGroupResponse.getPrivacyGroupId(), publicKeys.get(0)));
enclave.deletePrivacyGroup(privacyGroupResponse.getPrivacyGroupId(), publicKeys.get(0));
assertThat(privacyGroupResponse.getPrivacyGroupId()).isEqualTo(response);
}
@ -152,34 +137,27 @@ public class EnclaveTest {
List<String> 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);
PrivacyGroup privacyGroupResponse =
enclave.createPrivacyGroup(publicKeys, publicKeys.get(0), name, description);
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]));
PrivacyGroup[] findPrivacyGroupResponse = enclave.findPrivacyGroup(findPrivacyGroupRequest);
PrivacyGroup[] findPrivacyGroupResponse = enclave.findPrivacyGroup(publicKeys);
assertThat(findPrivacyGroupResponse.length).isEqualTo(1);
assertThat(findPrivacyGroupResponse[0].getPrivacyGroupId())
.isEqualTo(privacyGroupResponse.getPrivacyGroupId());
DeletePrivacyGroupRequest deletePrivacyGroupRequest =
new DeletePrivacyGroupRequest(privacyGroupResponse.getPrivacyGroupId(), publicKeys.get(0));
String response = enclave.deletePrivacyGroup(deletePrivacyGroupRequest);
String response =
enclave.deletePrivacyGroup(privacyGroupResponse.getPrivacyGroupId(), publicKeys.get(0));
assertThat(privacyGroupResponse.getPrivacyGroupId()).isEqualTo(response);
findPrivacyGroupRequest = new FindPrivacyGroupRequest(publicKeys.toArray(new String[0]));
findPrivacyGroupResponse = enclave.findPrivacyGroup(findPrivacyGroupRequest);
findPrivacyGroupResponse = enclave.findPrivacyGroup(publicKeys);
assertThat(findPrivacyGroupResponse.length).isEqualTo(0);
}

@ -22,11 +22,13 @@ import org.hyperledger.besu.enclave.types.FindPrivacyGroupRequest;
import org.hyperledger.besu.enclave.types.PrivacyGroup;
import org.hyperledger.besu.enclave.types.ReceiveRequest;
import org.hyperledger.besu.enclave.types.ReceiveResponse;
import org.hyperledger.besu.enclave.types.SendRequest;
import org.hyperledger.besu.enclave.types.SendRequestBesu;
import org.hyperledger.besu.enclave.types.SendRequestLegacy;
import org.hyperledger.besu.enclave.types.SendResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
@ -54,42 +56,72 @@ public class Enclave {
}
}
public SendResponse send(final SendRequest content) {
public SendResponse send(
final String payload, final String privateFrom, final List<String> privateFor) {
final SendRequestLegacy request = new SendRequestLegacy(payload, privateFrom, privateFor);
return post(
JSON,
content,
request,
"/send",
(statusCode, body) -> handleJsonResponse(statusCode, body, SendResponse.class));
}
public ReceiveResponse receive(final ReceiveRequest content) {
public SendResponse send(
final String payload, final String privateFrom, final String privacyGroupId) {
final SendRequestBesu request = new SendRequestBesu(payload, privateFrom, privacyGroupId);
return post(
JSON,
request,
"/send",
(statusCode, body) -> handleJsonResponse(statusCode, body, SendResponse.class));
}
public ReceiveResponse receive(final String enclaveKey) {
final ReceiveRequest request = new ReceiveRequest(enclaveKey);
return post(
ORION,
request,
"/receive",
(statusCode, body) -> handleJsonResponse(statusCode, body, ReceiveResponse.class));
}
public ReceiveResponse receive(final String enclaveKey, final String to) {
final ReceiveRequest request = new ReceiveRequest(enclaveKey, to);
return post(
ORION,
content,
request,
"/receive",
(statusCode, body) -> handleJsonResponse(statusCode, body, ReceiveResponse.class));
}
public PrivacyGroup createPrivacyGroup(final CreatePrivacyGroupRequest content) {
public PrivacyGroup createPrivacyGroup(
final List<String> addresses,
final String from,
final String name,
final String description) {
final CreatePrivacyGroupRequest request =
new CreatePrivacyGroupRequest(addresses, from, name, description);
return post(
JSON,
content,
request,
"/createPrivacyGroup",
(statusCode, body) -> handleJsonResponse(statusCode, body, PrivacyGroup.class));
}
public String deletePrivacyGroup(final DeletePrivacyGroupRequest content) {
public String deletePrivacyGroup(final String privacyGroupId, final String from) {
final DeletePrivacyGroupRequest request = new DeletePrivacyGroupRequest(privacyGroupId, from);
return post(
JSON,
content,
request,
"/deletePrivacyGroup",
(statusCode, body) -> handleJsonResponse(statusCode, body, String.class));
}
public PrivacyGroup[] findPrivacyGroup(final FindPrivacyGroupRequest content) {
public PrivacyGroup[] findPrivacyGroup(final List<String> addresses) {
final FindPrivacyGroupRequest request = new FindPrivacyGroupRequest(addresses);
return post(
JSON,
content,
request,
"/findPrivacyGroup",
(statusCode, body) -> handleJsonResponse(statusCode, body, PrivacyGroup[].class));
}

@ -14,19 +14,21 @@
*/
package org.hyperledger.besu.enclave.types;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class CreatePrivacyGroupRequest {
private final String[] addresses;
private final List<String> addresses;
private final String from;
private final String name;
private final String description;
@JsonCreator
public CreatePrivacyGroupRequest(
@JsonProperty("addresses") final String[] addresses,
@JsonProperty("addresses") final List<String> addresses,
@JsonProperty("from") final String from,
@JsonProperty("name") final String name,
@JsonProperty("description") final String description) {
@ -37,7 +39,7 @@ public class CreatePrivacyGroupRequest {
}
@JsonProperty("addresses")
public String[] addresses() {
public List<String> addresses() {
return addresses;
}

@ -14,20 +14,22 @@
*/
package org.hyperledger.besu.enclave.types;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class FindPrivacyGroupRequest {
private final String[] addresses;
private final List<String> addresses;
@JsonCreator
public FindPrivacyGroupRequest(@JsonProperty("addresses") final String[] addresses) {
public FindPrivacyGroupRequest(@JsonProperty("addresses") final List<String> addresses) {
this.addresses = addresses;
}
@JsonProperty("addresses")
public String[] addresses() {
public List<String> addresses() {
return addresses;
}
}

@ -15,6 +15,7 @@
package org.hyperledger.besu.enclave.types;
import java.io.Serializable;
import java.util.List;
public class PrivacyGroup implements Serializable {
@ -22,7 +23,7 @@ public class PrivacyGroup implements Serializable {
private String name;
private String description;
private Type type;
private String[] members;
private List<String> members;
public String getPrivacyGroupId() {
return privacyGroupId;
@ -56,11 +57,11 @@ public class PrivacyGroup implements Serializable {
this.type = type;
}
public String[] getMembers() {
public List<String> getMembers() {
return members;
}
public void setMembers(final String[] members) {
public void setMembers(final List<String> members) {
this.members = members;
}
@ -71,7 +72,7 @@ public class PrivacyGroup implements Serializable {
final Type type,
final String name,
final String description,
final String[] members) {
final List<String> members) {
this.privacyGroupId = privacyGroupId;
this.type = type;
this.name = name;

@ -23,8 +23,6 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.crypto.SECP256K1;
import org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.enclave.EnclaveFactory;
import org.hyperledger.besu.enclave.types.SendRequest;
import org.hyperledger.besu.enclave.types.SendRequestLegacy;
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;
@ -38,6 +36,7 @@ import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction;
import org.hyperledger.besu.ethereum.privacy.Restriction;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
@ -48,6 +47,7 @@ import org.hyperledger.orion.testutil.OrionTestHarness;
import org.hyperledger.orion.testutil.OrionTestHarnessFactory;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Optional;
@ -63,10 +63,12 @@ import org.junit.rules.TemporaryFolder;
public class PrivGetPrivateTransactionIntegrationTest {
@ClassRule public static final TemporaryFolder folder = new TemporaryFolder();
private static final String ENCLAVE_PUBLIC_KEY = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=";
private static Enclave enclave;
private static OrionTestHarness testHarness;
private static PrivacyController privacyController;
private final TransactionWithMetadata returnedTransaction = mock(TransactionWithMetadata.class);
@ -86,6 +88,8 @@ public class PrivGetPrivateTransactionIntegrationTest {
testHarness.start();
final EnclaveFactory factory = new EnclaveFactory(vertx);
enclave = factory.createVertxEnclave(testHarness.clientUrl());
privacyController = new PrivacyController(enclave, ENCLAVE_PUBLIC_KEY, null, null, null, null);
}
@AfterClass
@ -123,8 +127,7 @@ public class PrivGetPrivateTransactionIntegrationTest {
+ "daa4f6b2f003d1b0180029"))
.sender(sender)
.chainId(BigInteger.valueOf(2018))
.privateFrom(
BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8)))
.privateFrom(BytesValue.wrap(ENCLAVE_PUBLIC_KEY.getBytes(UTF_8)))
.privateFor(
Lists.newArrayList(
BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8))))
@ -145,7 +148,7 @@ public class PrivGetPrivateTransactionIntegrationTest {
public void returnsStoredPrivateTransaction() {
final PrivGetPrivateTransaction privGetPrivateTransaction =
new PrivGetPrivateTransaction(blockchain, privacyParameters);
new PrivGetPrivateTransaction(blockchain, privacyController);
when(blockchain.transactionByHash(any(Hash.class)))
.thenReturn(Optional.of(returnedTransaction));
@ -154,12 +157,9 @@ public class PrivGetPrivateTransactionIntegrationTest {
final BytesValueRLPOutput bvrlp = new BytesValueRLPOutput();
privateTransaction.writeTo(bvrlp);
final SendRequest sendRequest =
new SendRequestLegacy(
Base64.getEncoder().encodeToString(bvrlp.encoded().extractArray()),
"A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=",
Lists.newArrayList("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="));
final SendResponse sendResponse = enclave.send(sendRequest);
final String payload = Base64.getEncoder().encodeToString(bvrlp.encoded().extractArray());
final ArrayList<String> to = Lists.newArrayList("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=");
final SendResponse sendResponse = enclave.send(payload, ENCLAVE_PUBLIC_KEY, to);
final BytesValue hexKey = BytesValues.fromBase64(sendResponse.getKey());
when(justTransaction.getPayload()).thenReturn(hexKey);

@ -12,32 +12,30 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv;
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods;
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.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.core.PrivacyParameters;
public abstract class PrivacyApiMethod implements JsonRpcMethod {
public class DisabledPrivacyRpcMethod implements JsonRpcMethod {
protected final PrivacyParameters privacyParameters;
private final String methodName;
protected PrivacyApiMethod(final PrivacyParameters privacyParameters) {
this.privacyParameters = privacyParameters;
@Override
public String getName() {
return methodName;
}
public DisabledPrivacyRpcMethod(final String methodName) {
this.methodName = methodName;
}
@Override
public final JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
if (privacyParameters.isEnabled()) {
return doResponse(requestContext);
} else {
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), JsonRpcError.PRIVACY_NOT_ENABLED);
}
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), JsonRpcError.PRIVACY_NOT_ENABLED);
}
public abstract JsonRpcResponse doResponse(final JsonRpcRequestContext request);
}

@ -17,39 +17,32 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods;
import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcErrorConverter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcRequestException;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivacyApiMethod;
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.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionHandler;
import org.hyperledger.besu.ethereum.privacy.Restriction;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPException;
import org.hyperledger.besu.util.bytes.BytesValue;
import java.util.function.Supplier;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public abstract class PrivacySendTransaction extends PrivacyApiMethod {
public class PrivacySendTransaction {
private static final Logger LOG = LogManager.getLogger();
protected final PrivateTransactionHandler privateTransactionHandler;
protected final TransactionPool transactionPool;
protected final PrivacyController privacyController;
public PrivacySendTransaction(
final PrivacyParameters privacyParameters,
final PrivateTransactionHandler privateTransactionHandler,
final TransactionPool transactionPool) {
super(privacyParameters);
this.privateTransactionHandler = privateTransactionHandler;
this.transactionPool = transactionPool;
public PrivacySendTransaction(final PrivacyController privacyController) {
this.privacyController = privacyController;
}
protected PrivateTransaction validateAndDecodeRequest(final JsonRpcRequestContext request)
public PrivateTransaction validateAndDecodeRequest(final JsonRpcRequestContext request)
throws ErrorResponseException {
if (request.getRequest().getParamLength() != 1) {
throw new ErrorResponseException(
@ -75,15 +68,15 @@ public abstract class PrivacySendTransaction extends PrivacyApiMethod {
return privateTransaction;
}
protected JsonRpcResponse validateAndExecute(
public JsonRpcResponse validateAndExecute(
final JsonRpcRequestContext request,
final PrivateTransaction privateTransaction,
final String privacyGroupId,
final AfterTransactionValid afterValid) {
return privateTransactionHandler
final Supplier<JsonRpcResponse> successfulJsonRpcResponse) {
return privacyController
.validatePrivateTransaction(privateTransaction, privacyGroupId)
.either(
afterValid::getResponse,
successfulJsonRpcResponse,
(errorReason) ->
new JsonRpcErrorResponse(
request.getRequest().getId(),
@ -100,7 +93,7 @@ public abstract class PrivacySendTransaction extends PrivacyApiMethod {
}
}
protected static class ErrorResponseException extends Exception {
public static class ErrorResponseException extends Exception {
private final JsonRpcResponse response;
private ErrorResponseException(final JsonRpcResponse response) {
@ -112,8 +105,4 @@ public abstract class PrivacySendTransaction extends PrivacyApiMethod {
return response;
}
}
protected interface AfterTransactionValid {
JsonRpcResponse getResponse();
}
}

@ -18,23 +18,29 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcEnclaveErrorConverter;
import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcErrorConverter;
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.PrivacySendTransaction;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacySendTransaction.ErrorResponseException;
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.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionHandler;
import org.hyperledger.besu.ethereum.privacy.SendTransactionResponse;
public class EeaSendRawTransaction extends PrivacySendTransaction {
public class EeaSendRawTransaction implements JsonRpcMethod {
private final PrivacySendTransaction privacySendTransaction;
private TransactionPool transactionPool;
private PrivacyController privacyController;
public EeaSendRawTransaction(
final PrivacyParameters privacyParameters,
final PrivateTransactionHandler privateTransactionHandler,
final TransactionPool transactionPool) {
super(privacyParameters, privateTransactionHandler, transactionPool);
final TransactionPool transactionPool, final PrivacyController privacyController) {
this.transactionPool = transactionPool;
this.privacyController = privacyController;
this.privacySendTransaction = new PrivacySendTransaction(privacyController);
}
@Override
@ -43,40 +49,31 @@ public class EeaSendRawTransaction extends PrivacySendTransaction {
}
@Override
public JsonRpcResponse doResponse(final JsonRpcRequestContext requestContext) {
PrivateTransaction privateTransaction;
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
final PrivateTransaction privateTransaction;
try {
privateTransaction = validateAndDecodeRequest(requestContext);
} catch (ErrorResponseException e) {
privateTransaction = privacySendTransaction.validateAndDecodeRequest(requestContext);
} catch (final ErrorResponseException e) {
return e.getResponse();
}
final String enclaveKey;
try {
enclaveKey = privateTransactionHandler.sendToOrion(privateTransaction);
} catch (final Exception e) {
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(),
JsonRpcEnclaveErrorConverter.convertEnclaveInvalidReason(e.getMessage()));
}
final String privacyGroupId;
final SendTransactionResponse sendTransactionResponse;
try {
privacyGroupId = privateTransactionHandler.getPrivacyGroup(enclaveKey, privateTransaction);
sendTransactionResponse = privacyController.sendTransaction(privateTransaction);
} catch (final Exception e) {
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(),
JsonRpcEnclaveErrorConverter.convertEnclaveInvalidReason(e.getMessage()));
}
return validateAndExecute(
return privacySendTransaction.validateAndExecute(
requestContext,
privateTransaction,
privacyGroupId,
sendTransactionResponse.getPrivacyGroupId(),
() -> {
final Transaction privacyMarkerTransaction =
privateTransactionHandler.createPrivacyMarkerTransaction(
enclaveKey, privateTransaction);
privacyController.createPrivacyMarkerTransaction(
sendTransactionResponse.getEnclaveKey(), privateTransaction);
return transactionPool
.addLocalTransaction(privacyMarkerTransaction)
.either(

@ -16,28 +16,26 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv;
import static org.apache.logging.log4j.LogManager.getLogger;
import org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.enclave.types.CreatePrivacyGroupRequest;
import org.hyperledger.besu.enclave.types.PrivacyGroup;
import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcEnclaveErrorConverter;
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.parameters.CreatePrivacyGroupParameter;
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.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import org.apache.logging.log4j.Logger;
public class PrivCreatePrivacyGroup extends PrivacyApiMethod {
public class PrivCreatePrivacyGroup implements JsonRpcMethod {
private static final Logger LOG = getLogger();
private final Enclave enclave;
private PrivacyController privacyController;
public PrivCreatePrivacyGroup(final PrivacyParameters privacyParameters) {
super(privacyParameters);
this.enclave = privacyParameters.getEnclave();
public PrivCreatePrivacyGroup(final PrivacyController privacyController) {
this.privacyController = privacyController;
}
@Override
@ -46,7 +44,7 @@ public class PrivCreatePrivacyGroup extends PrivacyApiMethod {
}
@Override
public JsonRpcResponse doResponse(final JsonRpcRequestContext requestContext) {
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
LOG.trace("Executing {}", RpcMethod.PRIV_CREATE_PRIVACY_GROUP.getMethodName());
final CreatePrivacyGroupParameter parameter =
@ -57,15 +55,11 @@ public class PrivCreatePrivacyGroup extends PrivacyApiMethod {
parameter.getName(),
parameter.getDescription());
final CreatePrivacyGroupRequest createPrivacyGroupRequest =
new CreatePrivacyGroupRequest(
parameter.getAddresses(),
privacyParameters.getEnclavePublicKey(),
parameter.getName(),
parameter.getDescription());
final PrivacyGroup response;
try {
response = enclave.createPrivacyGroup(createPrivacyGroupRequest);
response =
privacyController.createPrivacyGroup(
parameter.getAddresses(), parameter.getName(), parameter.getDescription());
} catch (Exception e) {
LOG.error("Failed to create privacy group", e);
return new JsonRpcErrorResponse(

@ -16,25 +16,23 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv;
import static org.apache.logging.log4j.LogManager.getLogger;
import org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.enclave.types.DeletePrivacyGroupRequest;
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.response.JsonRpcError;
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.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import org.apache.logging.log4j.Logger;
public class PrivDeletePrivacyGroup extends PrivacyApiMethod {
public class PrivDeletePrivacyGroup implements JsonRpcMethod {
private static final Logger LOG = getLogger();
private final Enclave enclave;
private PrivacyController privacyController;
public PrivDeletePrivacyGroup(final PrivacyParameters privacyParameters) {
super(privacyParameters);
this.enclave = privacyParameters.getEnclave();
public PrivDeletePrivacyGroup(final PrivacyController privacyController) {
this.privacyController = privacyController;
}
@Override
@ -43,24 +41,16 @@ public class PrivDeletePrivacyGroup extends PrivacyApiMethod {
}
@Override
public JsonRpcResponse doResponse(final JsonRpcRequestContext requestContext) {
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
LOG.trace("Executing {}", RpcMethod.PRIV_DELETE_PRIVACY_GROUP.getMethodName());
final String privacyGroupId = requestContext.getRequiredParameter(0, String.class);
LOG.trace(
"Deleting a privacy group with privacyGroupId {} and from {}",
privacyGroupId,
privacyParameters.getEnclavePublicKey());
DeletePrivacyGroupRequest deletePrivacyGroupRequest =
new DeletePrivacyGroupRequest(privacyGroupId, privacyParameters.getEnclavePublicKey());
String response;
final String response;
try {
response = enclave.deletePrivacyGroup(deletePrivacyGroupRequest);
response = privacyController.deletePrivacyGroup(privacyGroupId);
} catch (Exception e) {
LOG.error("Failed to fetch transaction from Enclave with error " + e.getMessage());
LOG.error(e);
LOG.error("Failed to fetch transaction", e);
return new JsonRpcSuccessResponse(
requestContext.getRequest().getId(), JsonRpcError.DELETE_PRIVACY_GROUP_ERROR);
}

@ -17,23 +17,25 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv;
import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcEnclaveErrorConverter;
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.PrivacySendTransaction;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacySendTransaction.ErrorResponseException;
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.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionHandler;
import org.hyperledger.besu.ethereum.privacy.SendTransactionResponse;
import org.hyperledger.besu.util.bytes.BytesValues;
public class PrivDistributeRawTransaction extends PrivacySendTransaction {
public class PrivDistributeRawTransaction implements JsonRpcMethod {
public PrivDistributeRawTransaction(
final PrivacyParameters privacyParameters,
final PrivateTransactionHandler privateTransactionHandler,
final TransactionPool transactionPool) {
super(privacyParameters, privateTransactionHandler, transactionPool);
private final PrivacyController privacyController;
private final PrivacySendTransaction privacySendTransaction;
public PrivDistributeRawTransaction(final PrivacyController privacyController) {
this.privacyController = privacyController;
this.privacySendTransaction = new PrivacySendTransaction(privacyController);
}
@Override
@ -42,39 +44,30 @@ public class PrivDistributeRawTransaction extends PrivacySendTransaction {
}
@Override
public JsonRpcResponse doResponse(final JsonRpcRequestContext requestContext) {
PrivateTransaction privateTransaction;
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
final PrivateTransaction privateTransaction;
try {
privateTransaction = validateAndDecodeRequest(requestContext);
privateTransaction = privacySendTransaction.validateAndDecodeRequest(requestContext);
} catch (ErrorResponseException e) {
return e.getResponse();
}
final String enclaveKey;
try {
enclaveKey = privateTransactionHandler.sendToOrion(privateTransaction);
} catch (final Exception e) {
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(),
JsonRpcEnclaveErrorConverter.convertEnclaveInvalidReason(e.getMessage()));
}
final String privacyGroupId;
final SendTransactionResponse sendTransactionResponse;
try {
privacyGroupId = privateTransactionHandler.getPrivacyGroup(enclaveKey, privateTransaction);
sendTransactionResponse = privacyController.sendTransaction(privateTransaction);
} catch (final Exception e) {
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(),
JsonRpcEnclaveErrorConverter.convertEnclaveInvalidReason(e.getMessage()));
}
return validateAndExecute(
return privacySendTransaction.validateAndExecute(
requestContext,
privateTransaction,
privacyGroupId,
sendTransactionResponse.getPrivacyGroupId(),
() ->
new JsonRpcSuccessResponse(
requestContext.getRequest().getId(),
BytesValues.fromBase64(enclaveKey).toString()));
BytesValues.fromBase64(sendTransactionResponse.getEnclaveKey()).toString()));
}
}

@ -16,28 +16,27 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv;
import static org.apache.logging.log4j.LogManager.getLogger;
import org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.enclave.types.FindPrivacyGroupRequest;
import org.hyperledger.besu.enclave.types.PrivacyGroup;
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.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.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import java.util.Arrays;
import org.apache.logging.log4j.Logger;
public class PrivFindPrivacyGroup extends PrivacyApiMethod {
public class PrivFindPrivacyGroup implements JsonRpcMethod {
private static final Logger LOG = getLogger();
private final Enclave enclave;
private PrivacyController privacyController;
public PrivFindPrivacyGroup(final PrivacyParameters privacyParameters) {
super(privacyParameters);
this.enclave = privacyParameters.getEnclave();
public PrivFindPrivacyGroup(final PrivacyController privacyController) {
this.privacyController = privacyController;
}
@Override
@ -46,21 +45,19 @@ public class PrivFindPrivacyGroup extends PrivacyApiMethod {
}
@Override
public JsonRpcResponse doResponse(final JsonRpcRequestContext requestContext) {
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
LOG.trace("Executing {}", RpcMethod.PRIV_FIND_PRIVACY_GROUP.getMethodName());
final String[] addresses = requestContext.getRequiredParameter(0, String[].class);
LOG.trace("Finding a privacy group with members {}", Arrays.toString(addresses));
FindPrivacyGroupRequest findPrivacyGroupRequest = new FindPrivacyGroupRequest(addresses);
PrivacyGroup[] response;
try {
response = enclave.findPrivacyGroup(findPrivacyGroupRequest);
response = privacyController.findPrivacyGroup(Arrays.asList(addresses));
} catch (Exception e) {
LOG.error("Failed to fetch group from Enclave with error " + e.getMessage());
LOG.error(e);
return new JsonRpcSuccessResponse(
LOG.error("Failed to fetch privacy group", e);
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), JsonRpcError.FIND_PRIVACY_GROUP_ERROR);
}
return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), response);

@ -18,26 +18,25 @@ import static org.apache.logging.log4j.LogManager.getLogger;
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.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.api.jsonrpc.internal.results.Quantity;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import org.apache.logging.log4j.Logger;
public class PrivGetEeaTransactionCount extends PrivacyApiMethod {
public class PrivGetEeaTransactionCount implements JsonRpcMethod {
private static final Logger LOG = getLogger();
private final PrivateEeaNonceProvider nonceProvider;
private PrivacyController privacyController;
public PrivGetEeaTransactionCount(
final PrivacyParameters privacyParameters, final PrivateEeaNonceProvider nonceProvider) {
super(privacyParameters);
this.nonceProvider = nonceProvider;
public PrivGetEeaTransactionCount(final PrivacyController privacyController) {
this.privacyController = privacyController;
}
@Override
@ -46,7 +45,7 @@ public class PrivGetEeaTransactionCount extends PrivacyApiMethod {
}
@Override
public JsonRpcResponse doResponse(final JsonRpcRequestContext requestContext) {
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
if (requestContext.getRequest().getParamLength() != 3) {
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS);
@ -57,7 +56,7 @@ public class PrivGetEeaTransactionCount extends PrivacyApiMethod {
final String[] privateFor = requestContext.getRequiredParameter(2, String[].class);
try {
final long nonce = nonceProvider.determineNonce(privateFrom, privateFor, address);
final long nonce = privacyController.determineNonce(privateFrom, privateFor, address);
return new JsonRpcSuccessResponse(
requestContext.getRequest().getId(), Quantity.create(nonce));
} catch (final Exception e) {

@ -16,17 +16,17 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv;
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.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
public class PrivGetPrivacyPrecompileAddress extends PrivacyApiMethod {
public class PrivGetPrivacyPrecompileAddress implements JsonRpcMethod {
private final Integer privacyAddress;
public PrivGetPrivacyPrecompileAddress(final PrivacyParameters privacyParameters) {
super(privacyParameters);
privacyAddress = privacyParameters.getPrivacyAddress();
}
@ -36,7 +36,7 @@ public class PrivGetPrivacyPrecompileAddress extends PrivacyApiMethod {
}
@Override
public JsonRpcResponse doResponse(final JsonRpcRequestContext requestContext) {
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
return new JsonRpcSuccessResponse(
requestContext.getRequest().getId(), Address.privacyPrecompiled(privacyAddress).toString());
}

@ -16,11 +16,10 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv;
import static org.apache.logging.log4j.LogManager.getLogger;
import org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.enclave.types.ReceiveRequest;
import org.hyperledger.besu.enclave.types.ReceiveResponse;
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.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.PrivateTransactionGroupResult;
@ -28,25 +27,24 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.Privat
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata;
import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput;
import org.hyperledger.besu.util.bytes.BytesValues;
import org.apache.logging.log4j.Logger;
public class PrivGetPrivateTransaction extends PrivacyApiMethod {
public class PrivGetPrivateTransaction implements JsonRpcMethod {
private static final Logger LOG = getLogger();
private final BlockchainQueries blockchain;
private final Enclave enclave;
private final PrivacyController privacyController;
public PrivGetPrivateTransaction(
final BlockchainQueries blockchain, final PrivacyParameters privacyParameters) {
super(privacyParameters);
final BlockchainQueries blockchain, final PrivacyController privacyController) {
this.blockchain = blockchain;
this.enclave = privacyParameters.getEnclave();
this.privacyController = privacyController;
}
@Override
@ -55,7 +53,7 @@ public class PrivGetPrivateTransaction extends PrivacyApiMethod {
}
@Override
public JsonRpcResponse doResponse(final JsonRpcRequestContext requestContext) {
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
LOG.trace("Executing {}", RpcMethod.PRIV_GET_PRIVATE_TRANSACTION.getMethodName());
final Hash hash = requestContext.getRequiredParameter(0, Hash.class);
@ -66,12 +64,11 @@ public class PrivGetPrivateTransaction extends PrivacyApiMethod {
return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), null);
}
try {
ReceiveResponse receiveResponse =
getReceiveResponseFromEnclave(
BytesValues.asBase64String(resultTransaction.getTransaction().getPayload()),
privacyParameters.getEnclavePublicKey());
LOG.trace("Received transaction information from Enclave");
LOG.trace("Fetching transaction information");
final ReceiveResponse receiveResponse =
privacyController.retrieveTransaction(
BytesValues.asBase64String(resultTransaction.getTransaction().getPayload()));
LOG.trace("Received transaction information");
final BytesValueRLPInput bytesValueRLPInput =
new BytesValueRLPInput(BytesValues.fromBase64(receiveResponse.getPayload()), false);
@ -86,18 +83,9 @@ public class PrivGetPrivateTransaction extends PrivacyApiMethod {
requestContext.getRequest().getId(),
new PrivateTransactionLegacyResult(privateTransaction));
}
} catch (Exception e) {
LOG.error("Failed to fetch private transaction with error " + e.getMessage());
} catch (final Exception e) {
LOG.error("Failed to fetch private transaction", e);
return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), null);
}
}
private ReceiveResponse getReceiveResponseFromEnclave(
final String enclaveKey, final String publicKey) throws Exception {
LOG.trace("Fetching transaction information from Enclave");
final ReceiveRequest enclaveRequest = new ReceiveRequest(enclaveKey, publicKey);
ReceiveResponse enclaveResponse = enclave.receive(enclaveRequest);
LOG.trace("Received transaction information from Enclave");
return enclaveResponse;
}
}

@ -16,24 +16,21 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv;
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.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.api.jsonrpc.internal.results.Quantity;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionHandler;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
public class PrivGetTransactionCount extends PrivacyApiMethod {
public class PrivGetTransactionCount implements JsonRpcMethod {
private final PrivateTransactionHandler privateTransactionHandler;
private final PrivacyController privacyController;
public PrivGetTransactionCount(
final PrivacyParameters privacyParameters,
final PrivateTransactionHandler privateTransactionHandler) {
super(privacyParameters);
this.privateTransactionHandler = privateTransactionHandler;
public PrivGetTransactionCount(final PrivacyController privacyController) {
this.privacyController = privacyController;
}
@Override
@ -42,7 +39,7 @@ public class PrivGetTransactionCount extends PrivacyApiMethod {
}
@Override
public JsonRpcResponse doResponse(final JsonRpcRequestContext requestContext) {
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
if (requestContext.getRequest().getParamLength() != 2) {
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS);
@ -51,7 +48,7 @@ public class PrivGetTransactionCount extends PrivacyApiMethod {
final Address address = requestContext.getRequiredParameter(0, Address.class);
final String privacyGroupId = requestContext.getRequiredParameter(1, String.class);
final long nonce = privateTransactionHandler.getSenderNonce(address, privacyGroupId);
final long nonce = privacyController.determineNonce(address, privacyGroupId);
return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), Quantity.create(nonce));
}
}

@ -16,13 +16,12 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv;
import static org.apache.logging.log4j.LogManager.getLogger;
import org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.enclave.EnclaveException;
import org.hyperledger.besu.enclave.types.ReceiveRequest;
import org.hyperledger.besu.enclave.types.ReceiveResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcEnclaveErrorConverter;
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.response.JsonRpcError;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
@ -36,6 +35,7 @@ import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.core.Log;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput;
import org.hyperledger.besu.ethereum.rlp.RLP;
@ -49,18 +49,21 @@ import java.util.Optional;
import org.apache.logging.log4j.Logger;
public class PrivGetTransactionReceipt extends PrivacyApiMethod {
public class PrivGetTransactionReceipt implements JsonRpcMethod {
private static final Logger LOG = getLogger();
private final BlockchainQueries blockchain;
private final Enclave enclave;
private PrivacyParameters privacyParameters;
private PrivacyController privacyController;
public PrivGetTransactionReceipt(
final BlockchainQueries blockchain, final PrivacyParameters privacyParameters) {
super(privacyParameters);
final BlockchainQueries blockchain,
final PrivacyParameters privacyParameters,
final PrivacyController privacyController) {
this.blockchain = blockchain;
this.enclave = privacyParameters.getEnclave();
this.privacyParameters = privacyParameters;
this.privacyController = privacyController;
}
@Override
@ -69,7 +72,7 @@ public class PrivGetTransactionReceipt extends PrivacyApiMethod {
}
@Override
public JsonRpcResponse doResponse(final JsonRpcRequestContext requestContext) {
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
LOG.trace("Executing {}", RpcMethod.PRIV_GET_TRANSACTION_RECEIPT.getMethodName());
final Hash transactionHash = requestContext.getRequiredParameter(0, Hash.class);
final Optional<TransactionLocation> maybeLocation =
@ -85,12 +88,13 @@ public class PrivGetTransactionReceipt extends PrivacyApiMethod {
final Hash blockhash = location.getBlockHash();
final long blockNumber = blockchain.getBlockchain().getBlockHeader(blockhash).get().getNumber();
final String publicKey = privacyParameters.getEnclavePublicKey();
final PrivateTransaction privateTransaction;
final String privacyGroupId;
try {
final ReceiveResponse receiveResponse = getReceiveResponseFromEnclave(transaction, publicKey);
LOG.trace("Received transaction information from Enclave");
final ReceiveResponse receiveResponse =
privacyController.retrieveTransaction(
BytesValues.asBase64String(transaction.getPayload()));
LOG.trace("Received transaction information");
final BytesValueRLPInput bytesValueRLPInput =
new BytesValueRLPInput(BytesValues.fromBase64(receiveResponse.getPayload()), false);
@ -167,16 +171,6 @@ public class PrivGetTransactionReceipt extends PrivacyApiMethod {
return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), result);
}
private ReceiveResponse getReceiveResponseFromEnclave(
final Transaction transaction, final String publicKey) {
LOG.trace("Fetching transaction information from Enclave");
final ReceiveRequest enclaveRequest =
new ReceiveRequest(BytesValues.asBase64String(transaction.getPayload()), publicKey);
final ReceiveResponse enclaveResponse = enclave.receive(enclaveRequest);
LOG.trace("Received transaction information from Enclave");
return enclaveResponse;
}
private JsonRpcResponse handleEnclaveException(
final JsonRpcRequestContext requestContext, final EnclaveException e) {
final JsonRpcError jsonRpcError =

@ -1,69 +0,0 @@
/*
* 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 org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.enclave.types.FindPrivacyGroupRequest;
import org.hyperledger.besu.enclave.types.PrivacyGroup;
import org.hyperledger.besu.enclave.types.PrivacyGroup.Type;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionHandler;
import java.util.List;
import java.util.stream.Collectors;
import com.google.common.collect.Lists;
import org.bouncycastle.util.Arrays;
public class PrivateEeaNonceProvider {
private final Enclave enclave;
private final PrivateTransactionHandler privateTransactionHandler;
public PrivateEeaNonceProvider(
final Enclave enclave, final PrivateTransactionHandler privateTransactionHandler) {
this.enclave = enclave;
this.privateTransactionHandler = privateTransactionHandler;
}
public long determineNonce(
final String privateFrom, final String[] privateFor, final Address address) {
final String[] groupMembers = Arrays.append(privateFor, privateFrom);
final FindPrivacyGroupRequest request = new FindPrivacyGroupRequest(groupMembers);
final List<PrivacyGroup> matchingGroups = Lists.newArrayList(enclave.findPrivacyGroup(request));
final List<PrivacyGroup> legacyGroups =
matchingGroups.stream()
.filter(group -> group.getType() == Type.LEGACY)
.collect(Collectors.toList());
if (legacyGroups.size() == 0) {
// the legacy group does not exist yet
return 0;
}
if (legacyGroups.size() != 1) {
throw new RuntimeException(
String.format(
"Found invalid number of privacy groups (%d), expected 1.", legacyGroups.size()));
}
final String privacyGroupId = legacyGroups.get(0).getPrivacyGroupId();
return privateTransactionHandler.getSenderNonce(address, privacyGroupId);
}
}

@ -14,13 +14,15 @@
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.parameters;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
public class CreatePrivacyGroupParameter {
private final String[] addresses;
private final List<String> addresses;
@JsonInclude(JsonInclude.Include.NON_NULL)
private final String name;
@ -30,7 +32,7 @@ public class CreatePrivacyGroupParameter {
@JsonCreator
public CreatePrivacyGroupParameter(
@JsonProperty(value = "addresses", required = true) final String[] addresses,
@JsonProperty(value = "addresses", required = true) final List<String> addresses,
@JsonProperty("name") final String name,
@JsonProperty("description") final String description) {
this.addresses = addresses;
@ -38,7 +40,7 @@ public class CreatePrivacyGroupParameter {
this.description = description;
}
public String[] getAddresses() {
public List<String> getAddresses() {
return addresses;
}

@ -19,12 +19,11 @@ 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.eea.EeaSendRawTransaction;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivGetEeaTransactionCount;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivateEeaNonceProvider;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionHandler;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import java.util.Map;
@ -44,14 +43,9 @@ public class EeaJsonRpcMethods extends PrivacyApiGroupJsonRpcMethods {
}
@Override
protected Map<String, JsonRpcMethod> create(
final PrivateTransactionHandler privateTransactionHandler) {
protected Map<String, JsonRpcMethod> create(final PrivacyController privacyController) {
return mapOf(
new EeaSendRawTransaction(
getPrivacyParameters(), privateTransactionHandler, getTransactionPool()),
new PrivGetEeaTransactionCount(
getPrivacyParameters(),
new PrivateEeaNonceProvider(
getPrivacyParameters().getEnclave(), privateTransactionHandler)));
new EeaSendRawTransaction(getTransactionPool(), privacyController),
new PrivGetEeaTransactionCount(privacyController));
}
}

@ -29,7 +29,7 @@ import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionHandler;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import java.util.Map;
@ -49,17 +49,16 @@ public class PrivJsonRpcMethods extends PrivacyApiGroupJsonRpcMethods {
}
@Override
protected Map<String, JsonRpcMethod> create(
final PrivateTransactionHandler privateTransactionHandler) {
protected Map<String, JsonRpcMethod> create(final PrivacyController privacyController) {
return mapOf(
new PrivGetTransactionReceipt(getBlockchainQueries(), getPrivacyParameters()),
new PrivCreatePrivacyGroup(getPrivacyParameters()),
new PrivDeletePrivacyGroup(getPrivacyParameters()),
new PrivFindPrivacyGroup(getPrivacyParameters()),
new PrivGetTransactionReceipt(
getBlockchainQueries(), getPrivacyParameters(), privacyController),
new PrivCreatePrivacyGroup(privacyController),
new PrivDeletePrivacyGroup(privacyController),
new PrivFindPrivacyGroup(privacyController),
new PrivGetPrivacyPrecompileAddress(getPrivacyParameters()),
new PrivGetTransactionCount(getPrivacyParameters(), privateTransactionHandler),
new PrivGetPrivateTransaction(getBlockchainQueries(), getPrivacyParameters()),
new PrivDistributeRawTransaction(
getPrivacyParameters(), privateTransactionHandler, getTransactionPool()));
new PrivGetTransactionCount(privacyController),
new PrivGetPrivateTransaction(getBlockchainQueries(), privacyController),
new PrivDistributeRawTransaction(privacyController));
}
}

@ -16,18 +16,21 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.methods;
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.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionHandler;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import org.hyperledger.besu.ethereum.privacy.markertransaction.FixedKeySigningPrivateMarkerTransactionFactory;
import org.hyperledger.besu.ethereum.privacy.markertransaction.PrivateMarkerTransactionFactory;
import org.hyperledger.besu.ethereum.privacy.markertransaction.RandomSigningPrivateMarkerTransactionFactory;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
public abstract class PrivacyApiGroupJsonRpcMethods extends ApiGroupJsonRpcMethods {
@ -69,15 +72,19 @@ public abstract class PrivacyApiGroupJsonRpcMethods extends ApiGroupJsonRpcMetho
createPrivateMarkerTransactionFactory(
privacyParameters, blockchainQueries, transactionPool.getPendingTransactions());
final PrivateTransactionHandler privateTransactionHandler =
new PrivateTransactionHandler(
final PrivacyController privacyController =
new PrivacyController(
privacyParameters, protocolSchedule.getChainId(), markerTransactionFactory);
return create(privateTransactionHandler);
return create(privacyController).entrySet().stream()
.collect(
Collectors.toMap(
Entry::getKey,
rpcMethod ->
createPrivacyMethod(privacyParameters.isEnabled(), rpcMethod.getValue())));
}
protected abstract Map<String, JsonRpcMethod> create(
final PrivateTransactionHandler privateTransactionHandler);
protected abstract Map<String, JsonRpcMethod> create(final PrivacyController privacyController);
private PrivateMarkerTransactionFactory createPrivateMarkerTransactionFactory(
final PrivacyParameters privacyParameters,
@ -95,4 +102,8 @@ public abstract class PrivacyApiGroupJsonRpcMethods extends ApiGroupJsonRpcMetho
}
return new RandomSigningPrivateMarkerTransactionFactory(privateContractAddress);
}
private JsonRpcMethod createPrivacyMethod(final Boolean enabled, final JsonRpcMethod rpcMethod) {
return enabled ? rpcMethod : new DisabledPrivacyRpcMethod(rpcMethod.getName());
}
}

@ -21,21 +21,21 @@ 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.priv.PrivGetEeaTransactionCount;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivateEeaNonceProvider;
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.core.Address;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import org.junit.Before;
import org.junit.Test;
public class PrivGetEeaTransactionCountTest {
private final PrivateEeaNonceProvider nonceProvider = mock(PrivateEeaNonceProvider.class);
private final PrivacyParameters privacyParameters = mock(PrivacyParameters.class);
private final PrivacyController privacyController = mock(PrivacyController.class);
private JsonRpcRequestContext request;
private final String privateFrom = "thePrivateFromKey";
@ -54,10 +54,10 @@ public class PrivGetEeaTransactionCountTest {
@Test
public void validRequestProducesExpectedNonce() {
final long reportedNonce = 8L;
final PrivGetEeaTransactionCount method =
new PrivGetEeaTransactionCount(privacyParameters, nonceProvider);
final PrivGetEeaTransactionCount method = new PrivGetEeaTransactionCount(privacyController);
when(nonceProvider.determineNonce(privateFrom, privateFor, address)).thenReturn(reportedNonce);
when(privacyController.determineNonce(privateFrom, privateFor, address))
.thenReturn(reportedNonce);
final JsonRpcResponse response = method.response(request);
assertThat(response).isInstanceOf(JsonRpcSuccessResponse.class);
@ -69,10 +69,9 @@ public class PrivGetEeaTransactionCountTest {
@Test
public void nonceProviderThrowsRuntimeExceptionProducesErrorResponse() {
final PrivGetEeaTransactionCount method =
new PrivGetEeaTransactionCount(privacyParameters, nonceProvider);
final PrivGetEeaTransactionCount method = new PrivGetEeaTransactionCount(privacyController);
when(nonceProvider.determineNonce(privateFrom, privateFor, address))
when(privacyController.determineNonce(privateFrom, privateFor, address))
.thenThrow(RuntimeException.class);
final JsonRpcResponse response = method.response(request);
@ -85,10 +84,9 @@ public class PrivGetEeaTransactionCountTest {
@Test
public void nonceProviderThrowsAnExceptionProducesErrorResponse() {
final PrivGetEeaTransactionCount method =
new PrivGetEeaTransactionCount(privacyParameters, nonceProvider);
final PrivGetEeaTransactionCount method = new PrivGetEeaTransactionCount(privacyController);
when(nonceProvider.determineNonce(privateFrom, privateFor, address))
when(privacyController.determineNonce(privateFrom, privateFor, address))
.thenThrow(RuntimeException.class);
final JsonRpcResponse response = method.response(request);
@ -98,18 +96,4 @@ public class PrivGetEeaTransactionCountTest {
assertThat(errorResponse.getError())
.isEqualTo(JsonRpcError.GET_PRIVATE_TRANSACTION_NONCE_ERROR);
}
@Test
public void returnPrivacyDisabledErrorWhenPrivacyIsDisabled() {
when(privacyParameters.isEnabled()).thenReturn(false);
final PrivGetEeaTransactionCount method =
new PrivGetEeaTransactionCount(privacyParameters, nonceProvider);
final JsonRpcRequestContext request =
new JsonRpcRequestContext(
new JsonRpcRequest("1", "priv_getEeaTransactionCount", new Object[] {}));
final JsonRpcErrorResponse response = (JsonRpcErrorResponse) method.response(request);
assertThat(response.getError()).isEqualTo(JsonRpcError.PRIVACY_NOT_ENABLED);
}
}

@ -1,113 +0,0 @@
/*
* 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.methods.privacy.eea;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.enclave.EnclaveException;
import org.hyperledger.besu.enclave.types.FindPrivacyGroupRequest;
import org.hyperledger.besu.enclave.types.PrivacyGroup;
import org.hyperledger.besu.enclave.types.PrivacyGroup.Type;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivateEeaNonceProvider;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionHandler;
import com.google.common.collect.Lists;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
public class PrivateEeaNonceProviderTest {
private final Address address = Address.fromHexString("55");
private final Enclave enclave = mock(Enclave.class);
private final PrivateTransactionHandler privateTransactionHandler =
mock(PrivateTransactionHandler.class);
private final PrivateEeaNonceProvider nonceProvider =
new PrivateEeaNonceProvider(enclave, privateTransactionHandler);
@Test
public void validRequestProducesExpectedNonce() {
final long reportedNonce = 8L;
final PrivacyGroup[] returnedGroups =
new PrivacyGroup[] {
new PrivacyGroup("Group1", Type.LEGACY, "Group1_Name", "Group1_Desc", new String[0]),
};
final ArgumentCaptor<FindPrivacyGroupRequest> groupMembersCaptor =
ArgumentCaptor.forClass(FindPrivacyGroupRequest.class);
when(enclave.findPrivacyGroup(groupMembersCaptor.capture())).thenReturn(returnedGroups);
when(privateTransactionHandler.getSenderNonce(address, "Group1")).thenReturn(reportedNonce);
final long nonce =
nonceProvider.determineNonce("privateFrom", new String[] {"first", "second"}, address);
assertThat(nonce).isEqualTo(reportedNonce);
assertThat(groupMembersCaptor.getValue().addresses())
.containsAll(Lists.newArrayList("privateFrom", "first", "second"));
}
@Test
public void noMatchingLegacyGroupsProducesExpectedNonce() {
final long reportedNonce = 0L;
final PrivacyGroup[] returnedGroups = new PrivacyGroup[0];
final ArgumentCaptor<FindPrivacyGroupRequest> groupMembersCaptor =
ArgumentCaptor.forClass(FindPrivacyGroupRequest.class);
when(enclave.findPrivacyGroup(groupMembersCaptor.capture())).thenReturn(returnedGroups);
when(privateTransactionHandler.getSenderNonce(address, "Group1")).thenReturn(reportedNonce);
final long nonce =
nonceProvider.determineNonce("privateFrom", new String[] {"first", "second"}, address);
assertThat(nonce).isEqualTo(reportedNonce);
assertThat(groupMembersCaptor.getValue().addresses())
.containsAll(Lists.newArrayList("privateFrom", "first", "second"));
}
@Test
public void moreThanOneMatchingLegacyGroupThrowsException() {
final PrivacyGroup[] returnedGroups =
new PrivacyGroup[] {
new PrivacyGroup("Group1", Type.LEGACY, "Group1_Name", "Group1_Desc", new String[0]),
new PrivacyGroup("Group2", Type.LEGACY, "Group2_Name", "Group2_Desc", new String[0]),
};
when(enclave.findPrivacyGroup(any())).thenReturn(returnedGroups);
assertThatExceptionOfType(RuntimeException.class)
.isThrownBy(
() ->
nonceProvider.determineNonce(
"privateFrom", new String[] {"first", "second"}, address));
}
@Test
public void enclaveThrowingAnExceptionResultsInErrorResponse() {
when(enclave.findPrivacyGroup(any())).thenThrow(new EnclaveException("Enclave Failed"));
assertThatExceptionOfType(EnclaveException.class)
.isThrownBy(
() ->
nonceProvider.determineNonce(
"privateFrom", new String[] {"first", "second"}, address));
}
}

@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.eea;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
@ -29,14 +30,14 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorR
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.core.Address;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.TransactionValidator.TransactionInvalidReason;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionHandler;
import org.hyperledger.besu.ethereum.privacy.SendTransactionResponse;
import org.hyperledger.besu.util.bytes.BytesValue;
import java.math.BigInteger;
@ -113,14 +114,11 @@ public class EeaSendRawTransactionTest {
@Mock private EeaSendRawTransaction method;
@Mock private PrivateTransactionHandler privateTxHandler;
@Mock private PrivacyParameters privacyParameters;
@Mock private PrivacyController privacyController;
@Before
public void before() {
when(privacyParameters.isEnabled()).thenReturn(true);
method = new EeaSendRawTransaction(privacyParameters, privateTxHandler, transactionPool);
method = new EeaSendRawTransaction(transactionPool, privacyController);
}
@Test
@ -196,14 +194,13 @@ public class EeaSendRawTransactionTest {
}
@Test
public void validTransactionIsSentToTransactionPool() throws Exception {
when(privateTxHandler.sendToOrion(any(PrivateTransaction.class))).thenReturn(MOCK_ORION_KEY);
when(privateTxHandler.getPrivacyGroup(any(String.class), any(PrivateTransaction.class)))
.thenReturn(MOCK_PRIVACY_GROUP);
when(privateTxHandler.validatePrivateTransaction(
public void validTransactionIsSentToTransactionPool() {
when(privacyController.sendTransaction(any(PrivateTransaction.class)))
.thenReturn(new SendTransactionResponse(MOCK_ORION_KEY, MOCK_PRIVACY_GROUP));
when(privacyController.validatePrivateTransaction(
any(PrivateTransaction.class), any(String.class)))
.thenReturn(ValidationResult.valid());
when(privateTxHandler.createPrivacyMarkerTransaction(
when(privacyController.createPrivacyMarkerTransaction(
any(String.class), any(PrivateTransaction.class)))
.thenReturn(PUBLIC_TRANSACTION);
when(transactionPool.addLocalTransaction(any(Transaction.class)))
@ -221,24 +218,22 @@ public class EeaSendRawTransactionTest {
final JsonRpcResponse actualResponse = method.response(request);
assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse);
verify(privateTxHandler).sendToOrion(any(PrivateTransaction.class));
verify(privateTxHandler).getPrivacyGroup(any(String.class), any(PrivateTransaction.class));
verify(privateTxHandler)
verify(privacyController).sendTransaction(any(PrivateTransaction.class));
verify(privacyController)
.validatePrivateTransaction(any(PrivateTransaction.class), any(String.class));
verify(privateTxHandler)
verify(privacyController)
.createPrivacyMarkerTransaction(any(String.class), any(PrivateTransaction.class));
verify(transactionPool).addLocalTransaction(any(Transaction.class));
}
@Test
public void validTransactionPrivacyGroupIsSentToTransactionPool() throws Exception {
when(privateTxHandler.sendToOrion(any(PrivateTransaction.class))).thenReturn(MOCK_ORION_KEY);
when(privateTxHandler.getPrivacyGroup(any(String.class), any(PrivateTransaction.class)))
.thenReturn(MOCK_PRIVACY_GROUP);
when(privateTxHandler.validatePrivateTransaction(
public void validTransactionPrivacyGroupIsSentToTransactionPool() {
when(privacyController.sendTransaction(any(PrivateTransaction.class)))
.thenReturn(new SendTransactionResponse(MOCK_ORION_KEY, MOCK_PRIVACY_GROUP));
when(privacyController.validatePrivateTransaction(
any(PrivateTransaction.class), any(String.class)))
.thenReturn(ValidationResult.valid());
when(privateTxHandler.createPrivacyMarkerTransaction(
when(privacyController.createPrivacyMarkerTransaction(
any(String.class), any(PrivateTransaction.class)))
.thenReturn(PUBLIC_TRANSACTION);
when(transactionPool.addLocalTransaction(any(Transaction.class)))
@ -259,17 +254,16 @@ public class EeaSendRawTransactionTest {
final JsonRpcResponse actualResponse = method.response(request);
assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse);
verify(privateTxHandler).sendToOrion(any(PrivateTransaction.class));
verify(privateTxHandler).getPrivacyGroup(any(String.class), any(PrivateTransaction.class));
verify(privateTxHandler)
verify(privacyController).sendTransaction(any(PrivateTransaction.class));
verify(privacyController)
.validatePrivateTransaction(any(PrivateTransaction.class), any(String.class));
verify(privateTxHandler)
verify(privacyController)
.createPrivacyMarkerTransaction(any(String.class), any(PrivateTransaction.class));
verify(transactionPool).addLocalTransaction(any(Transaction.class));
}
@Test
public void transactionPrivacyGroupNoPrivateFromReturnsError() throws Exception {
public void invalidTransactionWithoutPrivateFromFieldFailsWithDecodeError() {
final JsonRpcRequestContext request =
new JsonRpcRequestContext(
new JsonRpcRequest(
@ -283,12 +277,12 @@ public class EeaSendRawTransactionTest {
final JsonRpcResponse actualResponse = method.response(request);
assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse);
verifyZeroInteractions(privateTxHandler);
verifyZeroInteractions(privacyController);
}
@Test
public void invalidTransactionIsSentToTransactionPool() {
when(privateTxHandler.sendToOrion(any(PrivateTransaction.class)))
public void invalidTransactionIsNotSentToTransactionPool() {
when(privacyController.sendTransaction(any(PrivateTransaction.class)))
.thenThrow(new EnclaveException("enclave failed to execute"));
final JsonRpcRequestContext request =
@ -302,63 +296,62 @@ public class EeaSendRawTransactionTest {
final JsonRpcResponse actualResponse = method.response(request);
assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse);
verifyNoInteractions(transactionPool);
}
@Test
public void transactionWithNonceBelowAccountNonceIsRejected() throws Exception {
public void transactionWithNonceBelowAccountNonceIsRejected() {
verifyErrorForInvalidTransaction(
TransactionInvalidReason.NONCE_TOO_LOW, JsonRpcError.NONCE_TOO_LOW);
}
@Test
public void transactionWithNonceAboveAccountNonceIsRejected() throws Exception {
public void transactionWithNonceAboveAccountNonceIsRejected() {
verifyErrorForInvalidTransaction(
TransactionInvalidReason.INCORRECT_NONCE, JsonRpcError.INCORRECT_NONCE);
}
@Test
public void transactionWithInvalidSignatureIsRejected() throws Exception {
public void transactionWithInvalidSignatureIsRejected() {
verifyErrorForInvalidTransaction(
TransactionInvalidReason.INVALID_SIGNATURE, JsonRpcError.INVALID_TRANSACTION_SIGNATURE);
}
@Test
public void transactionWithIntrinsicGasExceedingGasLimitIsRejected() throws Exception {
public void transactionWithIntrinsicGasExceedingGasLimitIsRejected() {
verifyErrorForInvalidTransaction(
TransactionInvalidReason.INTRINSIC_GAS_EXCEEDS_GAS_LIMIT,
JsonRpcError.INTRINSIC_GAS_EXCEEDS_LIMIT);
}
@Test
public void transactionWithUpfrontGasExceedingAccountBalanceIsRejected() throws Exception {
public void transactionWithUpfrontGasExceedingAccountBalanceIsRejected() {
verifyErrorForInvalidTransaction(
TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE,
JsonRpcError.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE);
}
@Test
public void transactionWithGasLimitExceedingBlockGasLimitIsRejected() throws Exception {
public void transactionWithGasLimitExceedingBlockGasLimitIsRejected() {
verifyErrorForInvalidTransaction(
TransactionInvalidReason.EXCEEDS_BLOCK_GAS_LIMIT, JsonRpcError.EXCEEDS_BLOCK_GAS_LIMIT);
}
@Test
public void transactionWithNotWhitelistedSenderAccountIsRejected() throws Exception {
public void transactionWithNotWhitelistedSenderAccountIsRejected() {
verifyErrorForInvalidTransaction(
TransactionInvalidReason.TX_SENDER_NOT_AUTHORIZED, JsonRpcError.TX_SENDER_NOT_AUTHORIZED);
}
private void verifyErrorForInvalidTransaction(
final TransactionInvalidReason transactionInvalidReason, final JsonRpcError expectedError)
throws Exception {
final TransactionInvalidReason transactionInvalidReason, final JsonRpcError expectedError) {
when(privateTxHandler.sendToOrion(any(PrivateTransaction.class))).thenReturn(MOCK_ORION_KEY);
when(privateTxHandler.getPrivacyGroup(any(String.class), any(PrivateTransaction.class)))
.thenReturn(MOCK_PRIVACY_GROUP);
when(privateTxHandler.validatePrivateTransaction(
when(privacyController.sendTransaction(any(PrivateTransaction.class)))
.thenReturn(new SendTransactionResponse(MOCK_ORION_KEY, MOCK_PRIVACY_GROUP));
when(privacyController.validatePrivateTransaction(
any(PrivateTransaction.class), any(String.class)))
.thenReturn(ValidationResult.valid());
when(privateTxHandler.createPrivacyMarkerTransaction(
when(privacyController.createPrivacyMarkerTransaction(
any(String.class), any(PrivateTransaction.class)))
.thenReturn(PUBLIC_TRANSACTION);
when(transactionPool.addLocalTransaction(any(Transaction.class)))
@ -374,11 +367,10 @@ public class EeaSendRawTransactionTest {
final JsonRpcResponse actualResponse = method.response(request);
assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse);
verify(privateTxHandler).sendToOrion(any(PrivateTransaction.class));
verify(privateTxHandler).getPrivacyGroup(any(String.class), any(PrivateTransaction.class));
verify(privateTxHandler)
verify(privacyController).sendTransaction(any(PrivateTransaction.class));
verify(privacyController)
.validatePrivateTransaction(any(PrivateTransaction.class), any(String.class));
verify(privateTxHandler)
verify(privacyController)
.createPrivacyMarkerTransaction(any(String.class), any(PrivateTransaction.class));
verify(transactionPool).addLocalTransaction(any(Transaction.class));
}
@ -387,16 +379,4 @@ public class EeaSendRawTransactionTest {
public void getMethodReturnsExpectedName() {
assertThat(method.getName()).matches("eea_sendRawTransaction");
}
@Test
public void returnPrivacyDisabledErrorWhenPrivacyIsDisabled() {
when(privacyParameters.isEnabled()).thenReturn(false);
final JsonRpcRequestContext request =
new JsonRpcRequestContext(
new JsonRpcRequest("1", "eea_sendRawTransaction", new Object[] {}));
final JsonRpcErrorResponse response = (JsonRpcErrorResponse) method.response(request);
assertThat(response.getError()).isEqualTo(JsonRpcError.PRIVACY_NOT_ENABLED);
}
}

@ -22,7 +22,6 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.enclave.EnclaveException;
import org.hyperledger.besu.enclave.types.CreatePrivacyGroupRequest;
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;
@ -32,7 +31,11 @@ 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 org.assertj.core.util.Lists;
import org.junit.Before;
import org.junit.Test;
@ -41,16 +44,14 @@ public class PrivCreatePrivacyGroupTest {
private static final String FROM = "first participant";
private static final String NAME = "testName";
private static final String DESCRIPTION = "testDesc";
private static final String[] ADDRESSES = new String[] {FROM, "second participant"};
private static final List<String> ADDRESSES = Lists.newArrayList(FROM, "second participant");
private final Enclave enclave = mock(Enclave.class);
private final Enclave failingEnclave = mock(Enclave.class);
private final PrivacyParameters privacyParameters = mock(PrivacyParameters.class);
private final PrivacyController privacyController = mock(PrivacyController.class);
@Before
public void setUp() {
when(failingEnclave.createPrivacyGroup(any(CreatePrivacyGroupRequest.class)))
.thenThrow(new EnclaveException(""));
when(privacyParameters.getEnclave()).thenReturn(enclave);
when(privacyParameters.isEnabled()).thenReturn(true);
}
@ -60,11 +61,12 @@ public class PrivCreatePrivacyGroupTest {
final String expected = "a wonderful group";
final PrivacyGroup privacyGroup =
new PrivacyGroup(expected, PrivacyGroup.Type.PANTHEON, NAME, DESCRIPTION, ADDRESSES);
when(enclave.createPrivacyGroup(any(CreatePrivacyGroupRequest.class))).thenReturn(privacyGroup);
when(privacyController.createPrivacyGroup(ADDRESSES, NAME, DESCRIPTION))
.thenReturn(privacyGroup);
when(privacyParameters.getEnclavePublicKey()).thenReturn(FROM);
final PrivCreatePrivacyGroup privCreatePrivacyGroup =
new PrivCreatePrivacyGroup(privacyParameters);
new PrivCreatePrivacyGroup(privacyController);
final CreatePrivacyGroupParameter param =
new CreatePrivacyGroupParameter(ADDRESSES, NAME, DESCRIPTION);
@ -87,16 +89,16 @@ public class PrivCreatePrivacyGroupTest {
final String expected = "a wonderful group";
final PrivacyGroup privacyGroup =
new PrivacyGroup(expected, PrivacyGroup.Type.PANTHEON, NAME, DESCRIPTION, ADDRESSES);
when(enclave.createPrivacyGroup(any(CreatePrivacyGroupRequest.class))).thenReturn(privacyGroup);
when(privacyController.createPrivacyGroup(ADDRESSES, NAME, null)).thenReturn(privacyGroup);
when(privacyParameters.getEnclavePublicKey()).thenReturn(FROM);
final PrivCreatePrivacyGroup privCreatePrivacyGroup =
new PrivCreatePrivacyGroup(privacyParameters);
new PrivCreatePrivacyGroup(privacyController);
final Object[] params =
new Object[] {
new Object() {
public String[] getAddresses() {
public List<String> getAddresses() {
return ADDRESSES;
}
@ -122,16 +124,17 @@ public class PrivCreatePrivacyGroupTest {
final String expected = "a wonderful group";
final PrivacyGroup privacyGroup =
new PrivacyGroup(expected, PrivacyGroup.Type.PANTHEON, NAME, DESCRIPTION, ADDRESSES);
when(enclave.createPrivacyGroup(any(CreatePrivacyGroupRequest.class))).thenReturn(privacyGroup);
when(privacyController.createPrivacyGroup(ADDRESSES, null, DESCRIPTION))
.thenReturn(privacyGroup);
when(privacyParameters.getEnclavePublicKey()).thenReturn(FROM);
final PrivCreatePrivacyGroup privCreatePrivacyGroup =
new PrivCreatePrivacyGroup(privacyParameters);
new PrivCreatePrivacyGroup(privacyController);
final Object[] params =
new Object[] {
new Object() {
public String[] getAddresses() {
public List<String> getAddresses() {
return ADDRESSES;
}
@ -157,16 +160,16 @@ public class PrivCreatePrivacyGroupTest {
final String expected = "a wonderful group";
final PrivacyGroup privacyGroup =
new PrivacyGroup(expected, PrivacyGroup.Type.PANTHEON, NAME, DESCRIPTION, ADDRESSES);
when(enclave.createPrivacyGroup(any(CreatePrivacyGroupRequest.class))).thenReturn(privacyGroup);
when(privacyController.createPrivacyGroup(ADDRESSES, null, null)).thenReturn(privacyGroup);
when(privacyParameters.getEnclavePublicKey()).thenReturn(FROM);
final PrivCreatePrivacyGroup privCreatePrivacyGroup =
new PrivCreatePrivacyGroup(privacyParameters);
new PrivCreatePrivacyGroup(privacyController);
final Object[] params =
new Object[] {
new Object() {
public String[] getAddresses() {
public List<String> getAddresses() {
return ADDRESSES;
}
}
@ -189,11 +192,11 @@ public class PrivCreatePrivacyGroupTest {
final String expected = "a wonderful group";
final PrivacyGroup privacyGroup =
new PrivacyGroup(expected, PrivacyGroup.Type.PANTHEON, NAME, DESCRIPTION, ADDRESSES);
when(enclave.createPrivacyGroup(any(CreatePrivacyGroupRequest.class))).thenReturn(privacyGroup);
when(enclave.createPrivacyGroup(any(), any(), any(), any())).thenReturn(privacyGroup);
when(privacyParameters.getEnclavePublicKey()).thenReturn(FROM);
final PrivCreatePrivacyGroup privCreatePrivacyGroup =
new PrivCreatePrivacyGroup(privacyParameters);
new PrivCreatePrivacyGroup(privacyController);
final Object[] params =
new Object[] {
@ -222,7 +225,7 @@ public class PrivCreatePrivacyGroupTest {
public void returnsCorrectExceptionMissingParam() {
final PrivCreatePrivacyGroup privCreatePrivacyGroup =
new PrivCreatePrivacyGroup(privacyParameters);
new PrivCreatePrivacyGroup(privacyController);
final Object[] params = new Object[] {};
@ -238,9 +241,10 @@ public class PrivCreatePrivacyGroupTest {
@Test
public void returnsCorrectErrorEnclaveError() {
when(privacyParameters.getEnclave()).thenReturn(failingEnclave);
when(privacyController.createPrivacyGroup(ADDRESSES, NAME, DESCRIPTION))
.thenThrow(new EnclaveException(""));
final PrivCreatePrivacyGroup privCreatePrivacyGroup =
new PrivCreatePrivacyGroup(privacyParameters);
new PrivCreatePrivacyGroup(privacyController);
final CreatePrivacyGroupParameter param =
new CreatePrivacyGroupParameter(ADDRESSES, NAME, DESCRIPTION);
@ -257,19 +261,4 @@ public class PrivCreatePrivacyGroupTest {
assertThat(result).isEqualTo(JsonRpcError.ENCLAVE_ERROR);
}
@Test
public void returnPrivacyDisabledErrorWhenPrivacyIsDisabled() {
when(privacyParameters.isEnabled()).thenReturn(false);
final PrivCreatePrivacyGroup privCreatePrivacyGroup =
new PrivCreatePrivacyGroup(privacyParameters);
final JsonRpcRequestContext request =
new JsonRpcRequestContext(
new JsonRpcRequest("1", "priv_createPrivacyGroup", new Object[] {}));
final JsonRpcErrorResponse response =
(JsonRpcErrorResponse) privCreatePrivacyGroup.response(request);
assertThat(response.getError()).isEqualTo(JsonRpcError.PRIVACY_NOT_ENABLED);
}
}

@ -1,58 +0,0 @@
/*
* 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.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.response.JsonRpcError;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class PrivDeletePrivacyGroupTest {
@Mock private Enclave enclave;
@Mock private PrivacyParameters privacyParameters;
private PrivDeletePrivacyGroup privDeletePrivacyGroup;
@Before
public void before() {
when(privacyParameters.getEnclave()).thenReturn(enclave);
privDeletePrivacyGroup = new PrivDeletePrivacyGroup(privacyParameters);
}
@Test
public void returnPrivacyDisabledErrorWhenPrivacyIsDisabled() {
when(privacyParameters.isEnabled()).thenReturn(false);
final JsonRpcRequestContext request =
new JsonRpcRequestContext(
new JsonRpcRequest("1", "priv_deletePrivacyGroup", new Object[] {}));
final JsonRpcErrorResponse response =
(JsonRpcErrorResponse) privDeletePrivacyGroup.response(request);
assertThat(response.getError()).isEqualTo(JsonRpcError.PRIVACY_NOT_ENABLED);
}
}

@ -21,15 +21,12 @@ 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.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.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionHandler;
import org.hyperledger.besu.ethereum.privacy.SendTransactionResponse;
import org.hyperledger.besu.util.bytes.BytesValues;
import org.junit.Before;
@ -50,29 +47,20 @@ public class PrivDistributeRawTransactionTest {
+ "200e885ff29e973e2576b6600181d1b0a2b5294e30d9be4a1981"
+ "ffb33a0b8c8a72657374726963746564";
final String MOCK_ORION_KEY = "93Ky7lXwFkMc7+ckoFgUMku5bpr9tz4zhmWmk9RlNng=";
private final String MOCK_PRIVACY_GROUP = "";
@Mock private TransactionPool transactionPool;
@Mock private PrivDistributeRawTransaction method;
@Mock private PrivateTransactionHandler privateTxHandler;
@Mock private PrivacyParameters privacyParameters;
@Mock private PrivacyController privacyController;
@Before
public void before() {
when(privacyParameters.isEnabled()).thenReturn(true);
method = new PrivDistributeRawTransaction(privacyParameters, privateTxHandler, transactionPool);
method = new PrivDistributeRawTransaction(privacyController);
}
@Test
public void validTransactionHashReturnedAfterDistribute() throws Exception {
when(privateTxHandler.sendToOrion(any(PrivateTransaction.class))).thenReturn(MOCK_ORION_KEY);
when(privateTxHandler.getPrivacyGroup(any(String.class), any(PrivateTransaction.class)))
.thenReturn(MOCK_PRIVACY_GROUP);
when(privateTxHandler.validatePrivateTransaction(
public void validTransactionHashReturnedAfterDistribute() {
final String enclavePublicKey = "93Ky7lXwFkMc7+ckoFgUMku5bpr9tz4zhmWmk9RlNng=";
when(privacyController.sendTransaction(any(PrivateTransaction.class)))
.thenReturn(new SendTransactionResponse(enclavePublicKey, ""));
when(privacyController.validatePrivateTransaction(
any(PrivateTransaction.class), any(String.class)))
.thenReturn(ValidationResult.valid());
@ -85,26 +73,13 @@ public class PrivDistributeRawTransactionTest {
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(
request.getRequest().getId(), BytesValues.fromBase64(MOCK_ORION_KEY).toString());
request.getRequest().getId(), BytesValues.fromBase64(enclavePublicKey).toString());
final JsonRpcResponse actualResponse = method.response(request);
assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse);
verify(privateTxHandler).sendToOrion(any(PrivateTransaction.class));
verify(privateTxHandler).getPrivacyGroup(any(String.class), any(PrivateTransaction.class));
verify(privateTxHandler)
verify(privacyController).sendTransaction(any(PrivateTransaction.class));
verify(privacyController)
.validatePrivateTransaction(any(PrivateTransaction.class), any(String.class));
}
@Test
public void returnPrivacyDisabledErrorWhenPrivacyIsDisabled() {
when(privacyParameters.isEnabled()).thenReturn(false);
final JsonRpcRequestContext request =
new JsonRpcRequestContext(
new JsonRpcRequest("1", "priv_distributeRawTransaction", new Object[] {}));
final JsonRpcErrorResponse response = (JsonRpcErrorResponse) method.response(request);
assertThat(response.getError()).isEqualTo(JsonRpcError.PRIVACY_NOT_ENABLED);
}
}

@ -1,57 +0,0 @@
/*
* 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.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.response.JsonRpcError;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class PrivFindPrivacyGroupTest {
@Mock private Enclave enclave;
@Mock private PrivacyParameters privacyParameters;
private PrivFindPrivacyGroup privFindPrivacyGroup;
@Before
public void before() {
when(privacyParameters.getEnclave()).thenReturn(enclave);
privFindPrivacyGroup = new PrivFindPrivacyGroup(privacyParameters);
}
@Test
public void returnPrivacyDisabledErrorWhenPrivacyIsDisabled() {
when(privacyParameters.isEnabled()).thenReturn(false);
final JsonRpcRequestContext request =
new JsonRpcRequestContext(new JsonRpcRequest("1", "findPrivacyGroup", new Object[] {}));
final JsonRpcErrorResponse response =
(JsonRpcErrorResponse) privFindPrivacyGroup.response(request);
assertThat(response.getError()).isEqualTo(JsonRpcError.PRIVACY_NOT_ENABLED);
}
}

@ -20,15 +20,10 @@ 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.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.JsonRpcResponseType;
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.assertj.core.api.Assertions;
import org.junit.Test;
public class PrivGetPrivacyPrecompileAddressTest {
@ -54,23 +49,4 @@ public class PrivGetPrivacyPrecompileAddressTest {
assertThat(response.getResult()).isEqualTo(privacyAddress);
}
@Test
public void verifyErrorPrivacyDisabled() {
when(privacyParameters.getPrivacyAddress()).thenReturn(rawPrivacyAddress);
when(privacyParameters.isEnabled()).thenReturn(false);
final PrivGetPrivacyPrecompileAddress privGetPrivacyPrecompileAddress =
new PrivGetPrivacyPrecompileAddress(privacyParameters);
final JsonRpcRequestContext request =
new JsonRpcRequestContext(
new JsonRpcRequest("1", "priv_getPrivacyPrecompileAddress", new Object[0]));
final JsonRpcResponse response = privGetPrivacyPrecompileAddress.response(request);
assertThat(response.getType()).isEqualByComparingTo(JsonRpcResponseType.ERROR);
Assertions.assertThat(((JsonRpcErrorResponse) response).getError())
.isEqualByComparingTo(JsonRpcError.PRIVACY_NOT_ENABLED);
}
}

@ -17,17 +17,15 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.crypto.SECP256K1;
import org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.enclave.types.ReceiveRequest;
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.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.api.jsonrpc.internal.results.privacy.PrivateTransactionGroupResult;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.PrivateTransactionLegacyResult;
@ -39,6 +37,7 @@ import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction;
import org.hyperledger.besu.ethereum.privacy.Restriction;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
@ -95,14 +94,11 @@ public class PrivGetPrivateTransactionTest {
BytesValues.fromBase64("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);
@Before
public void before() {
@ -111,7 +107,7 @@ public class PrivGetPrivateTransactionTest {
}
@Test
public void returnsPrivateTransactionLegacy() throws Exception {
public void returnsPrivateTransactionLegacy() {
when(blockchain.transactionByHash(any(Hash.class)))
.thenReturn(Optional.of(returnedTransaction));
when(returnedTransaction.getTransaction()).thenReturn(justTransaction);
@ -127,14 +123,14 @@ public class PrivGetPrivateTransactionTest {
new PrivateTransactionLegacyResult(privateTransaction);
final PrivGetPrivateTransaction privGetPrivateTransaction =
new PrivGetPrivateTransaction(blockchain, privacyParameters);
new PrivGetPrivateTransaction(blockchain, privacyController);
final Object[] params = new Object[] {enclaveKey};
final JsonRpcRequestContext request =
new JsonRpcRequestContext(new JsonRpcRequest("1", "priv_getPrivateTransaction", params));
final BytesValueRLPOutput bvrlp = new BytesValueRLPOutput();
privateTransaction.writeTo(bvrlp);
when(enclave.receive(any(ReceiveRequest.class)))
when(privacyController.retrieveTransaction(anyString()))
.thenReturn(
new ReceiveResponse(
Base64.getEncoder().encodeToString(bvrlp.encoded().extractArray()).getBytes(UTF_8),
@ -147,7 +143,7 @@ public class PrivGetPrivateTransactionTest {
}
@Test
public void returnsPrivateTransactionGroup() throws Exception {
public void returnsPrivateTransactionGroup() {
when(blockchain.transactionByHash(any(Hash.class)))
.thenReturn(Optional.of(returnedTransaction));
when(returnedTransaction.getTransaction()).thenReturn(justTransaction);
@ -161,7 +157,7 @@ public class PrivGetPrivateTransactionTest {
new PrivateTransactionGroupResult(privateTransaction);
final PrivGetPrivateTransaction privGetPrivateTransaction =
new PrivGetPrivateTransaction(blockchain, privacyParameters);
new PrivGetPrivateTransaction(blockchain, privacyController);
final Object[] params = new Object[] {enclaveKey};
final JsonRpcRequestContext request =
@ -169,30 +165,16 @@ public class PrivGetPrivateTransactionTest {
final BytesValueRLPOutput bvrlp = new BytesValueRLPOutput();
privateTransaction.writeTo(bvrlp);
when(enclave.receive(any(ReceiveRequest.class)))
when(privacyController.retrieveTransaction(anyString()))
.thenReturn(
new ReceiveResponse(
Base64.getEncoder().encodeToString(bvrlp.encoded().extractArray()).getBytes(UTF_8),
""));
final JsonRpcSuccessResponse response =
(JsonRpcSuccessResponse) privGetPrivateTransaction.response(request);
final PrivateTransactionResult result = (PrivateTransactionResult) response.getResult();
assertThat(result).isEqualToComparingFieldByField(privateTransactionGroupResult);
}
@Test
public void returnPrivacyDisabledErrorWhenPrivacyIsDisabled() {
when(privacyParameters.isEnabled()).thenReturn(false);
final PrivGetPrivateTransaction privGetPrivateTransaction =
new PrivGetPrivateTransaction(blockchain, privacyParameters);
final JsonRpcRequestContext request =
new JsonRpcRequestContext(
new JsonRpcRequest("1", "priv_getPrivacyTransaction", new Object[] {}));
final JsonRpcErrorResponse response =
(JsonRpcErrorResponse) privGetPrivateTransaction.response(request);
assertThat(response.getError()).isEqualTo(JsonRpcError.PRIVACY_NOT_ENABLED);
}
}

@ -21,12 +21,10 @@ 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.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.Address;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionHandler;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import org.hyperledger.besu.util.bytes.BytesValue;
import org.hyperledger.besu.util.bytes.BytesValues;
@ -36,8 +34,7 @@ import org.junit.Test;
public class PrivGetTransactionCountTest {
private final PrivacyParameters privacyParameters = mock(PrivacyParameters.class);
private final PrivateTransactionHandler privateTransactionHandler =
mock(PrivateTransactionHandler.class);
private final PrivacyController privacyController = mock(PrivacyController.class);
private final String privacyGroupId =
BytesValues.asBase64String(BytesValue.wrap("0x123".getBytes(UTF_8)));
@ -49,13 +46,13 @@ public class PrivGetTransactionCountTest {
@Before
public void before() {
when(privacyParameters.isEnabled()).thenReturn(true);
when(privateTransactionHandler.getSenderNonce(senderAddress, privacyGroupId)).thenReturn(NONCE);
when(privacyController.determineNonce(senderAddress, privacyGroupId)).thenReturn(NONCE);
}
@Test
public void verifyTransactionCount() {
final PrivGetTransactionCount privGetTransactionCount =
new PrivGetTransactionCount(privacyParameters, privateTransactionHandler);
new PrivGetTransactionCount(privacyController);
final Object[] params = new Object[] {senderAddress, privacyGroupId};
final JsonRpcRequestContext request =
@ -66,19 +63,4 @@ public class PrivGetTransactionCountTest {
assertThat(response.getResult()).isEqualTo(String.format("0x%X", NONCE));
}
@Test
public void returnPrivacyDisabledErrorWhenPrivacyIsDisabled() {
when(privacyParameters.isEnabled()).thenReturn(false);
final PrivGetTransactionCount privGetTransactionCount =
new PrivGetTransactionCount(privacyParameters, privateTransactionHandler);
final JsonRpcRequestContext request =
new JsonRpcRequestContext(
new JsonRpcRequest("1", "priv_getTransactionCount", new Object[] {}));
final JsonRpcErrorResponse response =
(JsonRpcErrorResponse) privGetTransactionCount.response(request);
assertThat(response.getError()).isEqualTo(JsonRpcError.PRIVACY_NOT_ENABLED);
}
}

@ -18,6 +18,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -25,12 +26,9 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.crypto.SECP256K1;
import org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.enclave.EnclaveException;
import org.hyperledger.besu.enclave.types.ReceiveRequest;
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.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.api.jsonrpc.internal.results.Quantity;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.privacy.PrivateTransactionReceiptResult;
@ -44,6 +42,7 @@ import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction;
import org.hyperledger.besu.ethereum.privacy.Restriction;
import org.hyperledger.besu.ethereum.privacy.storage.PrivateStateStorage;
@ -143,18 +142,17 @@ public class PrivGetTransactionReceiptTest {
private final Enclave enclave = mock(Enclave.class);
private final PrivacyParameters privacyParameters = mock(PrivacyParameters.class);
private final PrivateStateStorage privateStateStorage = mock(PrivateStateStorage.class);
private final Enclave failingEnclave = mock(Enclave.class);
private final PrivacyController failingPrivacyController = mock(PrivacyController.class);
private final PrivacyController privacyController = mock(PrivacyController.class);
@Before
public void setUp() {
when(enclave.receive(any(ReceiveRequest.class)))
when(privacyController.retrieveTransaction(anyString()))
.thenReturn(
new ReceiveResponse(
Base64.getEncoder().encode(RLP.encode(privateTransaction::writeTo).extractArray()),
""));
when(failingEnclave.receive(any(ReceiveRequest.class))).thenThrow(EnclaveException.class);
when(blockchainQueries.getBlockchain()).thenReturn(blockchain);
final TransactionLocation transactionLocation = new TransactionLocation(Hash.EMPTY, 0);
when(blockchain.getTransactionLocation(nullable(Hash.class)))
@ -179,7 +177,7 @@ public class PrivGetTransactionReceiptTest {
when(privacyParameters.getEnclave()).thenReturn(enclave);
final PrivGetTransactionReceipt privGetTransactionReceipt =
new PrivGetTransactionReceipt(blockchainQueries, privacyParameters);
new PrivGetTransactionReceipt(blockchainQueries, privacyParameters, privacyController);
final Object[] params = new Object[] {transaction.getHash()};
final JsonRpcRequestContext request =
new JsonRpcRequestContext(new JsonRpcRequest("1", "priv_getTransactionReceipt", params));
@ -194,12 +192,12 @@ public class PrivGetTransactionReceiptTest {
@Test
public void enclavePayloadNotFoundResultsInSuccessButNullResponse() {
when(privacyParameters.getEnclave()).thenReturn(failingEnclave);
when(failingEnclave.receive(any(ReceiveRequest.class)))
when(failingPrivacyController.retrieveTransaction(anyString()))
.thenThrow(new EnclaveException("EnclavePayloadNotFound"));
final PrivGetTransactionReceipt privGetTransactionReceipt =
new PrivGetTransactionReceipt(blockchainQueries, privacyParameters);
new PrivGetTransactionReceipt(
blockchainQueries, privacyParameters, failingPrivacyController);
final Object[] params = new Object[] {transaction.getHash()};
final JsonRpcRequestContext request =
new JsonRpcRequestContext(new JsonRpcRequest("1", "priv_getTransactionReceipt", params));
@ -218,7 +216,7 @@ public class PrivGetTransactionReceiptTest {
when(privacyParameters.getEnclave()).thenReturn(enclave);
final PrivGetTransactionReceipt privGetTransactionReceipt =
new PrivGetTransactionReceipt(blockchainQueries, privacyParameters);
new PrivGetTransactionReceipt(blockchainQueries, privacyParameters, privacyController);
final Object[] params = new Object[] {transaction.getHash()};
final JsonRpcRequestContext request =
new JsonRpcRequestContext(new JsonRpcRequest("1", "priv_getTransactionReceipt", params));
@ -233,10 +231,11 @@ public class PrivGetTransactionReceiptTest {
@Test
public void enclaveConnectionIssueThrowsRuntimeException() {
when(privacyParameters.getEnclave()).thenReturn(failingEnclave);
when(failingPrivacyController.retrieveTransaction(anyString()))
.thenThrow(EnclaveException.class);
final PrivGetTransactionReceipt privGetTransactionReceipt =
new PrivGetTransactionReceipt(blockchainQueries, privacyParameters);
new PrivGetTransactionReceipt(
blockchainQueries, privacyParameters, failingPrivacyController);
final Object[] params = new Object[] {transaction.getHash()};
final JsonRpcRequestContext request =
new JsonRpcRequestContext(new JsonRpcRequest("1", "priv_getTransactionReceipt", params));
@ -247,12 +246,11 @@ public class PrivGetTransactionReceiptTest {
@Test
public void transactionReceiptContainsRevertReasonWhenInvalidTransactionOccurs() {
when(privacyParameters.getEnclave()).thenReturn(enclave);
when(privateStateStorage.getRevertReason(any(Bytes32.class)))
.thenReturn(Optional.of(BytesValue.fromHexString("0x01")));
final PrivGetTransactionReceipt privGetTransactionReceipt =
new PrivGetTransactionReceipt(blockchainQueries, privacyParameters);
new PrivGetTransactionReceipt(blockchainQueries, privacyParameters, privacyController);
final Object[] params = new Object[] {transaction.getHash()};
final JsonRpcRequest request = new JsonRpcRequest("1", "priv_getTransactionReceipt", params);
@ -265,31 +263,15 @@ public class PrivGetTransactionReceiptTest {
assertThat(result.getRevertReason()).isEqualTo("0x01");
}
@Test
public void returnPrivacyDisabledErrorWhenPrivacyIsDisabled() {
when(privacyParameters.getEnclave()).thenReturn(enclave);
when(privacyParameters.isEnabled()).thenReturn(false);
final PrivGetTransactionReceipt privGetTransactionReceipt =
new PrivGetTransactionReceipt(blockchainQueries, privacyParameters);
final JsonRpcRequestContext request =
new JsonRpcRequestContext(
new JsonRpcRequest("1", "priv_getTransactionReceipt", new Object[] {}));
final JsonRpcErrorResponse response =
(JsonRpcErrorResponse) privGetTransactionReceipt.response(request);
assertThat(response.getError()).isEqualTo(JsonRpcError.PRIVACY_NOT_ENABLED);
}
@Test
public void enclaveKeysCannotDecryptPayloadThrowsRuntimeException() {
final String keysCannotDecryptPayloadMsg = "EnclaveKeysCannotDecryptPayload";
when(privacyParameters.getEnclave()).thenReturn(enclave);
when(enclave.receive(any())).thenThrow(new EnclaveException(keysCannotDecryptPayloadMsg));
when(privacyController.retrieveTransaction(any()))
.thenThrow(new EnclaveException(keysCannotDecryptPayloadMsg));
final PrivGetTransactionReceipt privGetTransactionReceipt =
new PrivGetTransactionReceipt(blockchainQueries, privacyParameters);
new PrivGetTransactionReceipt(blockchainQueries, privacyParameters, privacyController);
final Object[] params = new Object[] {transaction.getHash()};
final JsonRpcRequestContext request =
new JsonRpcRequestContext(new JsonRpcRequest("1", "priv_getTransactionReceipt", params));

@ -0,0 +1,89 @@
/*
* 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.methods;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.PRIVACY_NOT_ENABLED;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis;
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.response.JsonRpcErrorResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponseType;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class PrivacyApiGroupJsonRpcMethodsTest {
@Mock private JsonRpcMethod rpcMethod;
@Mock private BlockchainQueries blockchainQueries;
@Mock private ProtocolSchedule<?> protocolSchedule;
@Mock private TransactionPool transactionPool;
@Mock private PrivacyParameters privacyParameters;
private PrivacyApiGroupJsonRpcMethods privacyApiGroupJsonRpcMethods;
@Before
public void setup() {
when(rpcMethod.getName()).thenReturn("priv_method");
privacyApiGroupJsonRpcMethods = createPrivacyApiGroupJsonRpcMethods();
}
@Test
public void rpcMethodsCreatedWhenPrivacyIsNotEnabledAreDisabled() {
final Map<String, JsonRpcMethod> rpcMethods = privacyApiGroupJsonRpcMethods.create();
assertThat(rpcMethods).hasSize(1);
final JsonRpcMethod privMethod = rpcMethods.get("priv_method");
final JsonRpcRequestContext request =
new JsonRpcRequestContext(new JsonRpcRequest("2.0", "priv_method", null));
final JsonRpcResponse response = privMethod.response(request);
assertThat(response.getType()).isEqualTo(JsonRpcResponseType.ERROR);
JsonRpcErrorResponse errorResponse = (JsonRpcErrorResponse) response;
assertThat(errorResponse.getError()).isEqualTo(PRIVACY_NOT_ENABLED);
}
private PrivacyApiGroupJsonRpcMethods createPrivacyApiGroupJsonRpcMethods() {
return new PrivacyApiGroupJsonRpcMethods(
blockchainQueries, protocolSchedule, transactionPool, privacyParameters) {
@Override
protected RpcApi getApiGroup() {
return RpcApis.PRIV;
}
@Override
protected Map<String, JsonRpcMethod> create(final PrivacyController privacyController) {
return mapOf(rpcMethod);
}
};
}
}

@ -24,8 +24,6 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.enclave.EnclaveFactory;
import org.hyperledger.besu.enclave.types.SendRequest;
import org.hyperledger.besu.enclave.types.SendRequestLegacy;
import org.hyperledger.besu.enclave.types.SendResponse;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.Address;
@ -86,7 +84,6 @@ public class PrivacyPrecompiledContractIntegrationTest {
private static OrionTestHarness testHarness;
private static WorldStateArchive worldStateArchive;
private static PrivateStateStorage privateStateStorage;
private static PrivateStateStorage.Updater storageUpdater;
private static Vertx vertx = Vertx.vertx();
private PrivateTransactionProcessor mockPrivateTxProcessor() {
@ -132,7 +129,7 @@ public class PrivacyPrecompiledContractIntegrationTest {
when(worldStateArchive.getMutable(any())).thenReturn(Optional.of(mutableWorldState));
privateStateStorage = mock(PrivateStateStorage.class);
storageUpdater = mock(PrivateStateStorage.Updater.class);
final PrivateStateStorage.Updater storageUpdater = mock(PrivateStateStorage.Updater.class);
when(storageUpdater.putLatestStateRoot(nullable(Bytes32.class), any()))
.thenReturn(storageUpdater);
when(storageUpdater.putTransactionLogs(nullable(Bytes32.class), any()))
@ -149,7 +146,7 @@ public class PrivacyPrecompiledContractIntegrationTest {
}
@Test
public void testUpCheck() throws InterruptedException {
public void testUpCheck() {
assertThat(enclave.upCheck()).isTrue();
}
@ -158,9 +155,8 @@ public class PrivacyPrecompiledContractIntegrationTest {
final List<String> publicKeys = testHarness.getPublicKeys();
final String s = new String(VALID_PRIVATE_TRANSACTION_RLP_BASE64, UTF_8);
final SendRequest sc =
new SendRequestLegacy(s, publicKeys.get(0), Lists.newArrayList(publicKeys.get(0)));
final SendResponse sr = enclave.send(sc);
final SendResponse sr =
enclave.send(s, publicKeys.get(0), Lists.newArrayList(publicKeys.get(0)));
final PrivacyPrecompiledContract privacyPrecompiledContract =
new PrivacyPrecompiledContract(
@ -180,9 +176,8 @@ public class PrivacyPrecompiledContractIntegrationTest {
publicKeys.add("noPrivateKey");
final String s = new String(VALID_PRIVATE_TRANSACTION_RLP_BASE64, UTF_8);
final SendRequest sc = new SendRequestLegacy(s, publicKeys.get(0), publicKeys);
final Throwable thrown = catchThrowable(() -> enclave.send(sc));
final Throwable thrown = catchThrowable(() -> enclave.send(s, publicKeys.get(0), publicKeys));
assertThat(thrown).hasMessageContaining("EnclaveDecodePublicKey");
}
@ -193,9 +188,8 @@ public class PrivacyPrecompiledContractIntegrationTest {
publicKeys.add("noPrivateKenoPrivateKenoPrivateKenoPrivateK");
final String s = new String(VALID_PRIVATE_TRANSACTION_RLP_BASE64, UTF_8);
final SendRequest sc = new SendRequestLegacy(s, publicKeys.get(0), publicKeys);
final Throwable thrown = catchThrowable(() -> enclave.send(sc));
final Throwable thrown = catchThrowable(() -> enclave.send(s, publicKeys.get(0), publicKeys));
assertThat(thrown).hasMessageContaining("NodeMissingPeerUrl");
}

@ -17,7 +17,6 @@ package org.hyperledger.besu.ethereum.mainnet.precompiles.privacy;
import static org.hyperledger.besu.crypto.Hash.keccak256;
import org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.enclave.types.ReceiveRequest;
import org.hyperledger.besu.enclave.types.ReceiveResponse;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.Hash;
@ -88,11 +87,9 @@ public class PrivacyPrecompiledContract extends AbstractPrecompiledContract {
@Override
public BytesValue compute(final BytesValue input, final MessageFrame messageFrame) {
final String key = BytesValues.asBase64String(input);
final ReceiveRequest receiveRequest = new ReceiveRequest(key);
final ReceiveResponse receiveResponse;
try {
receiveResponse = enclave.receive(receiveRequest);
receiveResponse = enclave.receive(key);
} catch (final Exception e) {
LOG.debug("Enclave probably does not have private transaction payload with key {}", key, e);
return BytesValue.EMPTY;

@ -15,11 +15,9 @@
package org.hyperledger.besu.ethereum.privacy;
import org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.enclave.types.ReceiveRequest;
import org.hyperledger.besu.enclave.types.PrivacyGroup;
import org.hyperledger.besu.enclave.types.PrivacyGroup.Type;
import org.hyperledger.besu.enclave.types.ReceiveResponse;
import org.hyperledger.besu.enclave.types.SendRequest;
import org.hyperledger.besu.enclave.types.SendRequestBesu;
import org.hyperledger.besu.enclave.types.SendRequestLegacy;
import org.hyperledger.besu.enclave.types.SendResponse;
import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
@ -38,10 +36,12 @@ import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class PrivateTransactionHandler {
public class PrivacyController {
private static final Logger LOG = LogManager.getLogger();
@ -52,7 +52,7 @@ public class PrivateTransactionHandler {
private final PrivateTransactionValidator privateTransactionValidator;
private final PrivateMarkerTransactionFactory privateMarkerTransactionFactory;
public PrivateTransactionHandler(
public PrivacyController(
final PrivacyParameters privacyParameters,
final Optional<BigInteger> chainId,
final PrivateMarkerTransactionFactory privateMarkerTransactionFactory) {
@ -65,7 +65,7 @@ public class PrivateTransactionHandler {
privateMarkerTransactionFactory);
}
public PrivateTransactionHandler(
public PrivacyController(
final Enclave enclave,
final String enclavePublicKey,
final PrivateStateStorage privateStateStorage,
@ -80,37 +80,41 @@ public class PrivateTransactionHandler {
this.privateMarkerTransactionFactory = privateMarkerTransactionFactory;
}
public String sendToOrion(final PrivateTransaction privateTransaction) {
final SendRequest sendRequest = createSendRequest(privateTransaction);
final SendResponse sendResponse;
public SendTransactionResponse sendTransaction(final PrivateTransaction privateTransaction) {
try {
LOG.trace("Storing private transaction in enclave");
sendResponse = enclave.send(sendRequest);
return sendResponse.getKey();
final SendResponse sendResponse = sendRequest(privateTransaction);
final String enclaveKey = sendResponse.getKey();
if (privateTransaction.getPrivacyGroupId().isPresent()) {
final String privacyGroupId =
BytesValues.asBase64String(privateTransaction.getPrivacyGroupId().get());
return new SendTransactionResponse(enclaveKey, privacyGroupId);
} else {
final String privateFrom = BytesValues.asBase64String(privateTransaction.getPrivateFrom());
final String privacyGroupId = getPrivacyGroupId(enclaveKey, privateFrom);
return new SendTransactionResponse(enclaveKey, privacyGroupId);
}
} catch (Exception e) {
LOG.error("Failed to store private transaction in enclave", e);
throw e;
}
}
public String getPrivacyGroup(final String key, final PrivateTransaction privateTransaction) {
if (privateTransaction.getPrivacyGroupId().isPresent()) {
return BytesValues.asBase64String(privateTransaction.getPrivacyGroupId().get());
}
final ReceiveRequest receiveRequest =
new ReceiveRequest(key, BytesValues.asBase64String(privateTransaction.getPrivateFrom()));
LOG.debug(
"Getting privacy group for {}",
BytesValues.asBase64String(privateTransaction.getPrivateFrom()));
final ReceiveResponse receiveResponse;
try {
receiveResponse = enclave.receive(receiveRequest);
return receiveResponse.getPrivacyGroupId();
} catch (final RuntimeException e) {
LOG.error("Failed to retrieve private transaction in enclave", e);
throw e;
}
public ReceiveResponse retrieveTransaction(final String enclaveKey) {
return enclave.receive(enclaveKey, enclavePublicKey);
}
public PrivacyGroup createPrivacyGroup(
final List<String> addresses, final String name, final String description) {
return enclave.createPrivacyGroup(addresses, enclavePublicKey, name, description);
}
public String deletePrivacyGroup(final String privacyGroupId) {
return enclave.deletePrivacyGroup(privacyGroupId, enclavePublicKey);
}
public PrivacyGroup[] findPrivacyGroup(final List<String> addresses) {
return enclave.findPrivacyGroup(addresses);
}
public Transaction createPrivacyMarkerTransaction(
@ -121,36 +125,36 @@ public class PrivateTransactionHandler {
public ValidationResult<TransactionValidator.TransactionInvalidReason> validatePrivateTransaction(
final PrivateTransaction privateTransaction, final String privacyGroupId) {
return privateTransactionValidator.validate(
privateTransaction, getSenderNonce(privateTransaction.getSender(), privacyGroupId));
privateTransaction, determineNonce(privateTransaction.getSender(), privacyGroupId));
}
private SendRequest createSendRequest(final PrivateTransaction privateTransaction) {
final BytesValueRLPOutput bvrlp = new BytesValueRLPOutput();
privateTransaction.writeTo(bvrlp);
final String payload = BytesValues.asBase64String(bvrlp.encoded());
public long determineNonce(
final String privateFrom, final String[] privateFor, final Address address) {
final List<String> groupMembers = Lists.asList(privateFrom, privateFor);
if (privateTransaction.getPrivacyGroupId().isPresent()) {
return new SendRequestBesu(
payload,
enclavePublicKey,
BytesValues.asBase64String(privateTransaction.getPrivacyGroupId().get()));
} else {
final List<String> privateFor =
privateTransaction.getPrivateFor().get().stream()
.map(BytesValues::asBase64String)
.collect(Collectors.toList());
final List<PrivacyGroup> matchingGroups =
Lists.newArrayList(enclave.findPrivacyGroup(groupMembers));
// FIXME: orion should accept empty privateFor
if (privateFor.isEmpty()) {
privateFor.add(BytesValues.asBase64String(privateTransaction.getPrivateFrom()));
}
final List<PrivacyGroup> legacyGroups =
matchingGroups.stream()
.filter(group -> group.getType() == Type.LEGACY)
.collect(Collectors.toList());
return new SendRequestLegacy(
payload, BytesValues.asBase64String(privateTransaction.getPrivateFrom()), privateFor);
if (legacyGroups.size() == 0) {
// the legacy group does not exist yet
return 0;
}
Preconditions.checkArgument(
legacyGroups.size() == 1,
String.format(
"Found invalid number of privacy groups (%d), expected 1.", legacyGroups.size()));
final String privacyGroupId = legacyGroups.get(0).getPrivacyGroupId();
return determineNonce(address, privacyGroupId);
}
public long getSenderNonce(final Address sender, final String privacyGroupId) {
public long determineNonce(final Address sender, final String privacyGroupId) {
return privateStateStorage
.getLatestStateRoot(BytesValues.fromBase64(privacyGroupId))
.map(
@ -173,4 +177,38 @@ public class PrivateTransactionHandler {
// private state does not exist
Account.DEFAULT_NONCE);
}
private SendResponse sendRequest(final PrivateTransaction privateTransaction) {
final BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput();
privateTransaction.writeTo(rlpOutput);
final String payload = BytesValues.asBase64String(rlpOutput.encoded());
if (privateTransaction.getPrivacyGroupId().isPresent()) {
return enclave.send(
payload,
enclavePublicKey,
BytesValues.asBase64String(privateTransaction.getPrivacyGroupId().get()));
} else {
final List<String> privateFor =
privateTransaction.getPrivateFor().get().stream()
.map(BytesValues::asBase64String)
.collect(Collectors.toList());
if (privateFor.isEmpty()) {
privateFor.add(BytesValues.asBase64String(privateTransaction.getPrivateFrom()));
}
return enclave.send(
payload, BytesValues.asBase64String(privateTransaction.getPrivateFrom()), privateFor);
}
}
private String getPrivacyGroupId(final String key, final String privateFrom) {
LOG.debug("Getting privacy group for {}", privateFrom);
try {
return enclave.receive(key, privateFrom).getPrivacyGroupId();
} catch (final RuntimeException e) {
LOG.error("Failed to retrieve private transaction in enclave", e);
throw e;
}
}
}

@ -0,0 +1,33 @@
/*
* 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.privacy;
public class SendTransactionResponse {
private final String enclaveKey;
private final String privacyGroupId;
public SendTransactionResponse(final String enclaveKey, final String privacyGroupId) {
this.enclaveKey = enclaveKey;
this.privacyGroupId = privacyGroupId;
}
public String getEnclaveKey() {
return enclaveKey;
}
public String getPrivacyGroupId() {
return privacyGroupId;
}
}

@ -23,7 +23,6 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.enclave.EnclaveException;
import org.hyperledger.besu.enclave.types.ReceiveRequest;
import org.hyperledger.besu.enclave.types.ReceiveResponse;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.Address;
@ -79,7 +78,7 @@ public class PrivacyPrecompiledContractTest {
private Enclave mockEnclave() {
final Enclave mockEnclave = mock(Enclave.class);
final ReceiveResponse response = new ReceiveResponse(VALID_PRIVATE_TRANSACTION_RLP_BASE64, "");
when(mockEnclave.receive(any(ReceiveRequest.class))).thenReturn(response);
when(mockEnclave.receive(any())).thenReturn(response);
return mockEnclave;
}
@ -107,7 +106,7 @@ public class PrivacyPrecompiledContractTest {
private Enclave brokenMockEnclave() {
final Enclave mockEnclave = mock(Enclave.class);
when(mockEnclave.receive(any(ReceiveRequest.class))).thenThrow(EnclaveException.class);
when(mockEnclave.receive(any())).thenThrow(EnclaveException.class);
return mockEnclave;
}

@ -0,0 +1,454 @@
/*
* 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.privacy;
import static com.google.common.collect.Lists.newArrayList;
import static java.util.Collections.emptyList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.hyperledger.besu.ethereum.mainnet.TransactionValidator.TransactionInvalidReason.INCORRECT_PRIVATE_NONCE;
import static org.hyperledger.besu.ethereum.mainnet.TransactionValidator.TransactionInvalidReason.PRIVATE_NONCE_TOO_LOW;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.crypto.SECP256K1;
import org.hyperledger.besu.crypto.SECP256K1.KeyPair;
import org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.enclave.EnclaveException;
import org.hyperledger.besu.enclave.types.PrivacyGroup;
import org.hyperledger.besu.enclave.types.PrivacyGroup.Type;
import org.hyperledger.besu.enclave.types.ReceiveResponse;
import org.hyperledger.besu.enclave.types.SendResponse;
import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.mainnet.TransactionValidator.TransactionInvalidReason;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
import org.hyperledger.besu.ethereum.privacy.markertransaction.FixedKeySigningPrivateMarkerTransactionFactory;
import org.hyperledger.besu.ethereum.privacy.storage.PrivateStateStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.util.bytes.BytesValue;
import org.hyperledger.besu.util.bytes.BytesValues;
import org.hyperledger.orion.testutil.OrionKeyUtils;
import java.math.BigInteger;
import java.util.List;
import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class PrivacyControllerTest {
private static final String TRANSACTION_KEY = "93Ky7lXwFkMc7+ckoFgUMku5bpr9tz4zhmWmk9RlNng=";
private static final KeyPair KEY_PAIR =
KeyPair.create(
SECP256K1.PrivateKey.create(
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<String> 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 PrivacyController privacyController;
private PrivacyController brokenPrivacyController;
private PrivateTransactionValidator privateTransactionValidator;
private Enclave enclave;
private Account account;
private String enclavePublicKey;
private PrivateStateStorage privateStateStorage;
private WorldStateArchive worldStateArchive;
private MutableWorldState mutableWorldState;
private final Hash hash = mock(Hash.class);
private static final Transaction PUBLIC_TRANSACTION =
Transaction.builder()
.nonce(0)
.gasPrice(Wei.of(1000))
.gasLimit(3000000)
.to(Address.fromHexString("0x627306090abab3a6e1400e9345bc60c78a8bef57"))
.value(Wei.ZERO)
.payload(BytesValues.fromBase64(TRANSACTION_KEY))
.sender(Address.fromHexString("0xfe3b557e8fb62b89f4916b721be55ceb828dbd73"))
.chainId(BigInteger.valueOf(2018))
.signAndBuild(KEY_PAIR);
private Enclave mockEnclave() {
Enclave mockEnclave = mock(Enclave.class);
SendResponse response = new SendResponse(TRANSACTION_KEY);
ReceiveResponse receiveResponse = new ReceiveResponse(new byte[0], "mock");
when(mockEnclave.send(anyString(), anyString(), anyList())).thenReturn(response);
when(mockEnclave.send(anyString(), anyString(), anyString())).thenReturn(response);
when(mockEnclave.receive(any(), any())).thenReturn(receiveResponse);
return mockEnclave;
}
private Enclave brokenMockEnclave() {
Enclave mockEnclave = mock(Enclave.class);
when(mockEnclave.send(anyString(), anyString(), anyList())).thenThrow(EnclaveException.class);
return mockEnclave;
}
private PrivateTransactionValidator mockPrivateTransactionValidator() {
PrivateTransactionValidator validator = mock(PrivateTransactionValidator.class);
when(validator.validate(any(), any())).thenReturn(ValidationResult.valid());
return validator;
}
@Before
public void setUp() throws Exception {
privateStateStorage = mock(PrivateStateStorage.class);
when(privateStateStorage.getLatestStateRoot(any(BytesValue.class)))
.thenReturn(Optional.of(hash));
worldStateArchive = mock(WorldStateArchive.class);
account = mock(Account.class);
when(account.getNonce()).thenReturn(1L);
mutableWorldState = mock(MutableWorldState.class);
when(worldStateArchive.getMutable(any(Hash.class))).thenReturn(Optional.of(mutableWorldState));
when(mutableWorldState.get(any(Address.class))).thenReturn(account);
enclavePublicKey = OrionKeyUtils.loadKey("orion_key_0.pub");
privateTransactionValidator = mockPrivateTransactionValidator();
enclave = mockEnclave();
privacyController =
new PrivacyController(
enclave,
enclavePublicKey,
privateStateStorage,
worldStateArchive,
privateTransactionValidator,
new FixedKeySigningPrivateMarkerTransactionFactory(
Address.DEFAULT_PRIVACY, (address) -> 0, KEY_PAIR));
brokenPrivacyController =
new PrivacyController(
brokenMockEnclave(),
enclavePublicKey,
privateStateStorage,
worldStateArchive,
privateTransactionValidator,
new FixedKeySigningPrivateMarkerTransactionFactory(
Address.DEFAULT_PRIVACY, (address) -> 0, KEY_PAIR));
}
@Test
public void sendsValidLegacyTransaction() {
final PrivateTransaction transaction = buildLegacyPrivateTransaction(1);
final SendTransactionResponse sendTransactionResponse =
privacyController.sendTransaction(transaction);
final ValidationResult<TransactionInvalidReason> validationResult =
privacyController.validatePrivateTransaction(
transaction, sendTransactionResponse.getPrivacyGroupId());
final Transaction markerTransaction =
privacyController.createPrivacyMarkerTransaction(
sendTransactionResponse.getEnclaveKey(), transaction);
assertThat(validationResult).isEqualTo(ValidationResult.valid());
assertThat(markerTransaction.contractAddress()).isEqualTo(PUBLIC_TRANSACTION.contractAddress());
assertThat(markerTransaction.getPayload()).isEqualTo(PUBLIC_TRANSACTION.getPayload());
assertThat(markerTransaction.getNonce()).isEqualTo(PUBLIC_TRANSACTION.getNonce());
assertThat(markerTransaction.getSender()).isEqualTo(PUBLIC_TRANSACTION.getSender());
assertThat(markerTransaction.getValue()).isEqualTo(PUBLIC_TRANSACTION.getValue());
}
@Test
public void sendValidBesuTransaction() {
final PrivateTransaction transaction = buildBesuPrivateTransaction(1);
final SendTransactionResponse sendTransactionResponse =
privacyController.sendTransaction(transaction);
final ValidationResult<TransactionInvalidReason> validationResult =
privacyController.validatePrivateTransaction(
transaction, transaction.getPrivacyGroupId().get().toString());
final Transaction markerTransaction =
privacyController.createPrivacyMarkerTransaction(
sendTransactionResponse.getEnclaveKey(), transaction);
assertThat(validationResult).isEqualTo(ValidationResult.valid());
assertThat(markerTransaction.contractAddress()).isEqualTo(PUBLIC_TRANSACTION.contractAddress());
assertThat(markerTransaction.getPayload()).isEqualTo(PUBLIC_TRANSACTION.getPayload());
assertThat(markerTransaction.getNonce()).isEqualTo(PUBLIC_TRANSACTION.getNonce());
assertThat(markerTransaction.getSender()).isEqualTo(PUBLIC_TRANSACTION.getSender());
assertThat(markerTransaction.getValue()).isEqualTo(PUBLIC_TRANSACTION.getValue());
}
@Test
public void sendTransactionWhenEnclaveFailsThrowsEnclaveError() {
assertThatExceptionOfType(EnclaveException.class)
.isThrownBy(() -> brokenPrivacyController.sendTransaction(buildLegacyPrivateTransaction()));
}
@Test
public void validateTransactionWithTooLowNonceReturnsError() {
when(privateTransactionValidator.validate(any(), any()))
.thenReturn(ValidationResult.invalid(PRIVATE_NONCE_TOO_LOW));
final PrivateTransaction transaction = buildLegacyPrivateTransaction(0);
final SendTransactionResponse sendTransactionResponse =
privacyController.sendTransaction(transaction);
final ValidationResult<TransactionInvalidReason> validationResult =
privacyController.validatePrivateTransaction(
transaction, sendTransactionResponse.getPrivacyGroupId());
assertThat(validationResult).isEqualTo(ValidationResult.invalid(PRIVATE_NONCE_TOO_LOW));
}
@Test
public void validateTransactionWithIncorrectNonceReturnsError() {
when(privateTransactionValidator.validate(any(), any()))
.thenReturn(ValidationResult.invalid(INCORRECT_PRIVATE_NONCE));
final PrivateTransaction transaction = buildLegacyPrivateTransaction(2);
final SendTransactionResponse sendTransactionResponse =
privacyController.sendTransaction(transaction);
final ValidationResult<TransactionInvalidReason> validationResult =
privacyController.validatePrivateTransaction(
transaction, sendTransactionResponse.getPrivacyGroupId());
assertThat(validationResult).isEqualTo(ValidationResult.invalid(INCORRECT_PRIVATE_NONCE));
}
@Test
public void retrievesTransaction() {
when(enclave.receive(anyString(), anyString()))
.thenReturn(new ReceiveResponse(PAYLOAD, PRIVACY_GROUP_ID));
final ReceiveResponse receiveResponse = privacyController.retrieveTransaction(TRANSACTION_KEY);
assertThat(receiveResponse.getPayload()).isEqualTo(PAYLOAD);
assertThat(receiveResponse.getPrivacyGroupId()).isEqualTo(PRIVACY_GROUP_ID);
verify(enclave).receive(TRANSACTION_KEY, enclavePublicKey);
}
@Test
public void createsPrivacyGroup() {
final PrivacyGroup enclavePrivacyGroupResponse =
new PrivacyGroup(
PRIVACY_GROUP_ID,
Type.PANTHEON,
PRIVACY_GROUP_NAME,
PRIVACY_GROUP_DESCRIPTION,
PRIVACY_GROUP_ADDRESSES);
when(enclave.createPrivacyGroup(any(), any(), any(), any()))
.thenReturn(enclavePrivacyGroupResponse);
final PrivacyGroup privacyGroup =
privacyController.createPrivacyGroup(
PRIVACY_GROUP_ADDRESSES, PRIVACY_GROUP_NAME, PRIVACY_GROUP_DESCRIPTION);
assertThat(privacyGroup).isEqualToComparingFieldByField(enclavePrivacyGroupResponse);
verify(enclave)
.createPrivacyGroup(
PRIVACY_GROUP_ADDRESSES,
enclavePublicKey,
PRIVACY_GROUP_NAME,
PRIVACY_GROUP_DESCRIPTION);
}
@Test
public void deletesPrivacyGroup() {
when(enclave.deletePrivacyGroup(anyString(), anyString())).thenReturn(PRIVACY_GROUP_ID);
final String deletedPrivacyGroupId = privacyController.deletePrivacyGroup(PRIVACY_GROUP_ID);
assertThat(deletedPrivacyGroupId).isEqualTo(PRIVACY_GROUP_ID);
verify(enclave).deletePrivacyGroup(PRIVACY_GROUP_ID, enclavePublicKey);
}
@Test
public void findsPrivacyGroup() {
final PrivacyGroup privacyGroup =
new PrivacyGroup(
PRIVACY_GROUP_ID,
Type.PANTHEON,
PRIVACY_GROUP_NAME,
PRIVACY_GROUP_DESCRIPTION,
PRIVACY_GROUP_ADDRESSES);
when(enclave.findPrivacyGroup(any())).thenReturn(new PrivacyGroup[] {privacyGroup});
final PrivacyGroup[] privacyGroups =
privacyController.findPrivacyGroup(PRIVACY_GROUP_ADDRESSES);
assertThat(privacyGroups).hasSize(1);
assertThat(privacyGroups[0]).isEqualToComparingFieldByField(privacyGroup);
verify(enclave).findPrivacyGroup(PRIVACY_GROUP_ADDRESSES);
}
@Test
public void determinesNonceForEeaRequest() {
final Address address = Address.fromHexString("55");
final long reportedNonce = 8L;
final PrivacyGroup[] returnedGroups =
new PrivacyGroup[] {
new PrivacyGroup("Group1", Type.LEGACY, "Group1_Name", "Group1_Desc", emptyList()),
};
when(enclave.findPrivacyGroup(any())).thenReturn(returnedGroups);
when(account.getNonce()).thenReturn(8L);
final long nonce =
privacyController.determineNonce("privateFrom", new String[] {"first", "second"}, address);
assertThat(nonce).isEqualTo(reportedNonce);
verify(enclave)
.findPrivacyGroup(
argThat((m) -> m.containsAll(newArrayList("first", "second", "privateFrom"))));
}
@Test
public void determineNonceForEeaRequestWithNoMatchingGroupReturnsZero() {
final long reportedNonce = 0L;
final Address address = Address.fromHexString("55");
final PrivacyGroup[] returnedGroups = new PrivacyGroup[0];
when(enclave.findPrivacyGroup(any())).thenReturn(returnedGroups);
final long nonce =
privacyController.determineNonce("privateFrom", new String[] {"first", "second"}, address);
assertThat(nonce).isEqualTo(reportedNonce);
verify(enclave)
.findPrivacyGroup(
argThat((m) -> m.containsAll(newArrayList("first", "second", "privateFrom"))));
}
@Test
public void determineNonceForEeaRequestWithMoreThanOneMatchingGroupThrowsException() {
final Address address = Address.fromHexString("55");
final PrivacyGroup[] returnedGroups =
new PrivacyGroup[] {
new PrivacyGroup("Group1", Type.LEGACY, "Group1_Name", "Group1_Desc", emptyList()),
new PrivacyGroup("Group2", Type.LEGACY, "Group2_Name", "Group2_Desc", emptyList()),
};
when(enclave.findPrivacyGroup(any())).thenReturn(returnedGroups);
assertThatExceptionOfType(RuntimeException.class)
.isThrownBy(
() ->
privacyController.determineNonce(
"privateFrom", new String[] {"first", "second"}, address));
}
@Test
public void determineNonceForPrivacyGroupRequestWhenAccountExists() {
final Address address = Address.fromHexString("55");
when(account.getNonce()).thenReturn(4L);
final long nonce = privacyController.determineNonce(address, "Group1");
assertThat(nonce).isEqualTo(4L);
verify(privateStateStorage).getLatestStateRoot(BytesValues.fromBase64("Group1"));
verify(worldStateArchive).getMutable(hash);
verify(mutableWorldState).get(address);
}
@Test
public void determineNonceForPrivacyGroupRequestWhenPrivateStateDoesNotExist() {
final Address address = Address.fromHexString("55");
when(privateStateStorage.getLatestStateRoot(BytesValues.fromBase64("Group1")))
.thenReturn(Optional.empty());
final long nonce = privacyController.determineNonce(address, "Group1");
assertThat(nonce).isEqualTo(Account.DEFAULT_NONCE);
verifyNoInteractions(worldStateArchive, mutableWorldState, account);
}
@Test
public void determineNonceForPrivacyGroupRequestWhenWorldStateDoesNotExist() {
final Address address = Address.fromHexString("55");
when(privateStateStorage.getLatestStateRoot(BytesValues.fromBase64("Group1")))
.thenReturn(Optional.of(hash));
when(worldStateArchive.getMutable(hash)).thenReturn(Optional.empty());
final long nonce = privacyController.determineNonce(address, "Group1");
assertThat(nonce).isEqualTo(Account.DEFAULT_NONCE);
verifyNoInteractions(mutableWorldState, account);
}
@Test
public void determineNonceForPrivacyGroupRequestWhenAccountDoesNotExist() {
final Address address = Address.fromHexString("55");
when(privateStateStorage.getLatestStateRoot(BytesValues.fromBase64("Group1")))
.thenReturn(Optional.of(hash));
when(worldStateArchive.getMutable(hash)).thenReturn(Optional.of(mutableWorldState));
when(mutableWorldState.get(address)).thenReturn(null);
final long nonce = privacyController.determineNonce(address, "Group1");
assertThat(nonce).isEqualTo(Account.DEFAULT_NONCE);
verifyNoInteractions(account);
}
private static PrivateTransaction buildLegacyPrivateTransaction() {
return buildLegacyPrivateTransaction(0);
}
private static PrivateTransaction buildLegacyPrivateTransaction(final long nonce) {
return buildPrivateTransaction(nonce)
.privateFrom(BytesValues.fromBase64("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="))
.privateFor(
newArrayList(
BytesValues.fromBase64("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="),
BytesValues.fromBase64("Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs=")))
.signAndBuild(KEY_PAIR);
}
private static PrivateTransaction buildBesuPrivateTransaction(final long nonce) {
return buildPrivateTransaction(nonce)
.privateFrom(BytesValues.fromBase64("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="))
.privacyGroupId(BytesValues.fromBase64("DyAOiF/ynpc+JXa2YAGB0bCitSlOMNm+ShmB/7M6C4w="))
.signAndBuild(KEY_PAIR);
}
private static PrivateTransaction.Builder buildPrivateTransaction(final long nonce) {
return PrivateTransaction.builder()
.nonce(nonce)
.gasPrice(Wei.of(1000))
.gasLimit(3000000)
.to(Address.fromHexString("0x627306090abab3a6e1400e9345bc60c78a8bef57"))
.value(Wei.ZERO)
.payload(BytesValue.fromHexString("0x"))
.sender(Address.fromHexString("0xfe3b557e8fb62b89f4916b721be55ceb828dbd73"))
.chainId(BigInteger.valueOf(2018))
.restriction(Restriction.RESTRICTED);
}
}

@ -1,255 +0,0 @@
/*
* 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.privacy;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.hyperledger.besu.ethereum.mainnet.TransactionValidator.TransactionInvalidReason.INCORRECT_PRIVATE_NONCE;
import static org.hyperledger.besu.ethereum.mainnet.TransactionValidator.TransactionInvalidReason.PRIVATE_NONCE_TOO_LOW;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.crypto.SECP256K1;
import org.hyperledger.besu.crypto.SECP256K1.KeyPair;
import org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.enclave.EnclaveException;
import org.hyperledger.besu.enclave.types.ReceiveRequest;
import org.hyperledger.besu.enclave.types.ReceiveResponse;
import org.hyperledger.besu.enclave.types.SendRequest;
import org.hyperledger.besu.enclave.types.SendResponse;
import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.mainnet.TransactionValidator.TransactionInvalidReason;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
import org.hyperledger.besu.ethereum.privacy.markertransaction.FixedKeySigningPrivateMarkerTransactionFactory;
import org.hyperledger.besu.ethereum.privacy.storage.PrivateStateStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.util.bytes.BytesValue;
import org.hyperledger.besu.util.bytes.BytesValues;
import org.hyperledger.orion.testutil.OrionKeyUtils;
import java.math.BigInteger;
import java.util.Optional;
import com.google.common.collect.Lists;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class PrivateTransactionHandlerTest {
private static final String TRANSACTION_KEY = "93Ky7lXwFkMc7+ckoFgUMku5bpr9tz4zhmWmk9RlNng=";
private static final KeyPair KEY_PAIR =
KeyPair.create(
SECP256K1.PrivateKey.create(
new BigInteger(
"8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", 16)));
private PrivateTransactionHandler privateTransactionHandler;
private PrivateTransactionHandler brokenPrivateTransactionHandler;
private PrivateTransactionValidator privateTransactionValidator;
private static final Transaction PUBLIC_TRANSACTION =
Transaction.builder()
.nonce(0)
.gasPrice(Wei.of(1000))
.gasLimit(3000000)
.to(Address.fromHexString("0x627306090abab3a6e1400e9345bc60c78a8bef57"))
.value(Wei.ZERO)
.payload(BytesValues.fromBase64(TRANSACTION_KEY))
.sender(Address.fromHexString("0xfe3b557e8fb62b89f4916b721be55ceb828dbd73"))
.chainId(BigInteger.valueOf(2018))
.signAndBuild(KEY_PAIR);
Enclave mockEnclave() {
Enclave mockEnclave = mock(Enclave.class);
SendResponse response = new SendResponse(TRANSACTION_KEY);
ReceiveResponse receiveResponse = new ReceiveResponse(new byte[0], "mock");
when(mockEnclave.send(any(SendRequest.class))).thenReturn(response);
when(mockEnclave.receive(any(ReceiveRequest.class))).thenReturn(receiveResponse);
return mockEnclave;
}
Enclave brokenMockEnclave() {
Enclave mockEnclave = mock(Enclave.class);
when(mockEnclave.send(any(SendRequest.class))).thenThrow(EnclaveException.class);
return mockEnclave;
}
PrivateTransactionValidator mockPrivateTransactionValidator() {
PrivateTransactionValidator validator = mock(PrivateTransactionValidator.class);
when(validator.validate(any(), any())).thenReturn(ValidationResult.valid());
return validator;
}
@Before
public void setUp() throws Exception {
PrivateStateStorage privateStateStorage = mock(PrivateStateStorage.class);
Hash mockHash = mock(Hash.class);
when(privateStateStorage.getLatestStateRoot(any(BytesValue.class)))
.thenReturn(Optional.of(mockHash));
WorldStateArchive worldStateArchive = mock(WorldStateArchive.class);
Account account = mock(Account.class);
when(account.getNonce()).thenReturn(1L);
MutableWorldState mutableWorldState = mock(MutableWorldState.class);
when(worldStateArchive.getMutable(any(Hash.class))).thenReturn(Optional.of(mutableWorldState));
when(mutableWorldState.get(any(Address.class))).thenReturn(account);
privateTransactionValidator = mockPrivateTransactionValidator();
privateTransactionHandler =
new PrivateTransactionHandler(
mockEnclave(),
OrionKeyUtils.loadKey("orion_key_0.pub"),
privateStateStorage,
worldStateArchive,
privateTransactionValidator,
new FixedKeySigningPrivateMarkerTransactionFactory(
Address.DEFAULT_PRIVACY, (address) -> 0, KEY_PAIR));
brokenPrivateTransactionHandler =
new PrivateTransactionHandler(
brokenMockEnclave(),
OrionKeyUtils.loadKey("orion_key_0.pub"),
privateStateStorage,
worldStateArchive,
privateTransactionValidator,
new FixedKeySigningPrivateMarkerTransactionFactory(
Address.DEFAULT_PRIVACY, (address) -> 0, KEY_PAIR));
}
@Test
public void validLegacyTransactionThroughHandler() throws Exception {
final PrivateTransaction transaction = buildLegacyPrivateTransaction(1);
final String enclaveKey = privateTransactionHandler.sendToOrion(transaction);
final String privacyGroupId =
privateTransactionHandler.getPrivacyGroup(enclaveKey, transaction);
final ValidationResult<TransactionInvalidReason> validationResult =
privateTransactionHandler.validatePrivateTransaction(transaction, privacyGroupId);
final Transaction markerTransaction =
privateTransactionHandler.createPrivacyMarkerTransaction(enclaveKey, transaction);
assertThat(validationResult).isEqualTo(ValidationResult.valid());
assertThat(markerTransaction.contractAddress()).isEqualTo(PUBLIC_TRANSACTION.contractAddress());
assertThat(markerTransaction.getPayload()).isEqualTo(PUBLIC_TRANSACTION.getPayload());
assertThat(markerTransaction.getNonce()).isEqualTo(PUBLIC_TRANSACTION.getNonce());
assertThat(markerTransaction.getSender()).isEqualTo(PUBLIC_TRANSACTION.getSender());
assertThat(markerTransaction.getValue()).isEqualTo(PUBLIC_TRANSACTION.getValue());
}
@Test
public void validBesuTransactionThroughHandler() throws Exception {
final PrivateTransaction transaction = buildBesuPrivateTransaction(1);
final String enclaveKey = privateTransactionHandler.sendToOrion(transaction);
final ValidationResult<TransactionInvalidReason> validationResult =
privateTransactionHandler.validatePrivateTransaction(
transaction, transaction.getPrivacyGroupId().get().toString());
final Transaction markerTransaction =
privateTransactionHandler.createPrivacyMarkerTransaction(enclaveKey, transaction);
assertThat(validationResult).isEqualTo(ValidationResult.valid());
assertThat(markerTransaction.contractAddress()).isEqualTo(PUBLIC_TRANSACTION.contractAddress());
assertThat(markerTransaction.getPayload()).isEqualTo(PUBLIC_TRANSACTION.getPayload());
assertThat(markerTransaction.getNonce()).isEqualTo(PUBLIC_TRANSACTION.getNonce());
assertThat(markerTransaction.getSender()).isEqualTo(PUBLIC_TRANSACTION.getSender());
assertThat(markerTransaction.getValue()).isEqualTo(PUBLIC_TRANSACTION.getValue());
}
@Test
public void enclaveIsDownWhileHandling() {
assertThatExceptionOfType(EnclaveException.class)
.isThrownBy(
() -> brokenPrivateTransactionHandler.sendToOrion(buildLegacyPrivateTransaction()));
}
@Test
public void nonceTooLowError() throws Exception {
when(privateTransactionValidator.validate(any(), any()))
.thenReturn(ValidationResult.invalid(PRIVATE_NONCE_TOO_LOW));
final PrivateTransaction transaction = buildLegacyPrivateTransaction(0);
final String enclaveKey = privateTransactionHandler.sendToOrion(transaction);
final String privacyGroupId =
privateTransactionHandler.getPrivacyGroup(enclaveKey, transaction);
final ValidationResult<TransactionInvalidReason> validationResult =
privateTransactionHandler.validatePrivateTransaction(transaction, privacyGroupId);
assertThat(validationResult).isEqualTo(ValidationResult.invalid(PRIVATE_NONCE_TOO_LOW));
}
@Test
public void incorrectNonceError() throws Exception {
when(privateTransactionValidator.validate(any(), any()))
.thenReturn(ValidationResult.invalid(INCORRECT_PRIVATE_NONCE));
final PrivateTransaction transaction = buildLegacyPrivateTransaction(2);
final String enclaveKey = privateTransactionHandler.sendToOrion(transaction);
final String privacyGroupId =
privateTransactionHandler.getPrivacyGroup(enclaveKey, transaction);
final ValidationResult<TransactionInvalidReason> validationResult =
privateTransactionHandler.validatePrivateTransaction(transaction, privacyGroupId);
assertThat(validationResult).isEqualTo(ValidationResult.invalid(INCORRECT_PRIVATE_NONCE));
}
private static PrivateTransaction buildLegacyPrivateTransaction() {
return buildLegacyPrivateTransaction(0);
}
private static PrivateTransaction buildLegacyPrivateTransaction(final long nonce) {
return buildPrivateTransaction(nonce)
.privateFrom(BytesValues.fromBase64("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="))
.privateFor(
Lists.newArrayList(
BytesValues.fromBase64("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="),
BytesValues.fromBase64("Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs=")))
.signAndBuild(KEY_PAIR);
}
private static PrivateTransaction buildBesuPrivateTransaction(final long nonce) {
return buildPrivateTransaction(nonce)
.privateFrom(BytesValues.fromBase64("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="))
.privacyGroupId(BytesValues.fromBase64("DyAOiF/ynpc+JXa2YAGB0bCitSlOMNm+ShmB/7M6C4w="))
.signAndBuild(KEY_PAIR);
}
private static PrivateTransaction.Builder buildPrivateTransaction(final long nonce) {
return PrivateTransaction.builder()
.nonce(nonce)
.gasPrice(Wei.of(1000))
.gasLimit(3000000)
.to(Address.fromHexString("0x627306090abab3a6e1400e9345bc60c78a8bef57"))
.value(Wei.ZERO)
.payload(BytesValue.fromHexString("0x"))
.sender(Address.fromHexString("0xfe3b557e8fb62b89f4916b721be55ceb828dbd73"))
.chainId(BigInteger.valueOf(2018))
.restriction(Restriction.RESTRICTED);
}
}
Loading…
Cancel
Save