diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Transaction.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Transaction.java
index 8b752ade5c..559dbf6955 100644
--- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Transaction.java
+++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Transaction.java
@@ -125,7 +125,7 @@ public class Transaction {
*
The {@code chainId} must be greater than 0 to be applied to a specific chain; otherwise
* it will default to any chain.
*/
- protected Transaction(
+ public Transaction(
final long nonce,
final Wei gasPrice,
final long gasLimit,
diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionHandler.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionHandler.java
new file mode 100644
index 0000000000..001cbee626
--- /dev/null
+++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionHandler.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2019 ConsenSys AG.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package tech.pegasys.pantheon.ethereum.privacy;
+
+import tech.pegasys.pantheon.ethereum.core.Address;
+import tech.pegasys.pantheon.ethereum.core.PrivacyParameters;
+import tech.pegasys.pantheon.ethereum.core.Transaction;
+import tech.pegasys.pantheon.ethereum.rlp.BytesValueRLPOutput;
+import tech.pegasys.pantheon.orion.Orion;
+import tech.pegasys.pantheon.orion.types.SendRequest;
+import tech.pegasys.pantheon.orion.types.SendResponse;
+import tech.pegasys.pantheon.util.bytes.BytesValue;
+import tech.pegasys.pantheon.util.bytes.BytesValues;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Base64;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+public class PrivateTransactionHandler {
+
+ private final Orion orion;
+ private final Address privacyPrecompileAddress;
+
+ public PrivateTransactionHandler(final PrivacyParameters privacyParameters) {
+ this(
+ new Orion(privacyParameters.getUrl()),
+ Address.privacyPrecompiled(privacyParameters.getPrivacyAddress()));
+ }
+
+ public PrivateTransactionHandler(final Orion orion, final Address privacyPrecompileAddress) {
+ this.orion = orion;
+ this.privacyPrecompileAddress = privacyPrecompileAddress;
+ }
+
+ public Transaction handle(final PrivateTransaction privateTransaction) throws IOException {
+ final SendRequest sendRequest = createSendRequest(privateTransaction);
+ final SendResponse sendResponse;
+ try {
+ sendResponse = orion.send(sendRequest);
+ } catch (IOException e) {
+ throw e;
+ }
+
+ return createPrivacyMarkerTransaction(sendResponse.getKey(), privateTransaction);
+ }
+
+ private SendRequest createSendRequest(final PrivateTransaction privateTransaction) {
+ final List privateFor =
+ privateTransaction
+ .getPrivateFor()
+ .stream()
+ .map(BytesValues::asString)
+ .collect(Collectors.toList());
+
+ final BytesValueRLPOutput bvrlp = new BytesValueRLPOutput();
+ privateTransaction.writeTo(bvrlp);
+
+ return new SendRequest(
+ Base64.getEncoder().encodeToString(bvrlp.encoded().extractArray()),
+ BytesValues.asString(privateTransaction.getPrivateFrom()),
+ privateFor);
+ }
+
+ private Transaction createPrivacyMarkerTransaction(
+ final String transactionEnclaveKey, final PrivateTransaction privateTransaction) {
+
+ return new Transaction(
+ privateTransaction.getNonce(),
+ privateTransaction.getGasPrice(),
+ privateTransaction.getGasLimit(),
+ Optional.of(privacyPrecompileAddress),
+ privateTransaction.getValue(),
+ privateTransaction.getSignature(),
+ BytesValue.wrap(transactionEnclaveKey.getBytes(Charset.defaultCharset())),
+ privateTransaction.getSender(),
+ privateTransaction.getChainId().getAsInt());
+ }
+}
diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionHandlerTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionHandlerTest.java
new file mode 100644
index 0000000000..7bd2916296
--- /dev/null
+++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionHandlerTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2019 ConsenSys AG.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package tech.pegasys.pantheon.ethereum.privacy;
+
+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.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import tech.pegasys.pantheon.crypto.SECP256K1;
+import tech.pegasys.pantheon.ethereum.core.Address;
+import tech.pegasys.pantheon.ethereum.core.Transaction;
+import tech.pegasys.pantheon.ethereum.core.Wei;
+import tech.pegasys.pantheon.orion.Orion;
+import tech.pegasys.pantheon.orion.types.SendRequest;
+import tech.pegasys.pantheon.orion.types.SendResponse;
+import tech.pegasys.pantheon.util.bytes.BytesValue;
+
+import java.io.IOException;
+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 = "My Transaction Key";
+ private static final String TRANSACTION_KEY_HEX = "0x4d79205472616e73616374696f6e204b6579";
+
+ PrivateTransactionHandler privateTransactionHandler;
+ PrivateTransactionHandler brokenPrivateTransactionHandler;
+
+ private static final PrivateTransaction VALID_PRIVATE_TRANSACTION =
+ new PrivateTransaction(
+ 0L,
+ Wei.of(1),
+ 21000L,
+ Optional.of(
+ Address.wrap(BytesValue.fromHexString("0x095e7baea6a6c7c4c2dfeb977efac326af552d87"))),
+ Wei.of(
+ new BigInteger(
+ "115792089237316195423570985008687907853269984665640564039457584007913129639935")),
+ SECP256K1.Signature.create(
+ new BigInteger(
+ "32886959230931919120748662916110619501838190146643992583529828535682419954515"),
+ new BigInteger(
+ "14473701025599600909210599917245952381483216609124029382871721729679842002948"),
+ Byte.valueOf("0")),
+ BytesValue.fromHexString("0x"),
+ Address.wrap(BytesValue.fromHexString("0x8411b12666f68ef74cace3615c9d5a377729d03f")),
+ 1,
+ BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8)),
+ Lists.newArrayList(
+ BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8)),
+ BytesValue.wrap("Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs=".getBytes(UTF_8))),
+ BytesValue.wrap("restricted".getBytes(UTF_8)));
+
+ private static final Transaction PUBLIC_TRANSACTION =
+ new Transaction(
+ 0L,
+ Wei.of(1),
+ 21000L,
+ Optional.of(Address.DEFAULT_PRIVACY),
+ Wei.of(
+ new BigInteger(
+ "115792089237316195423570985008687907853269984665640564039457584007913129639935")),
+ SECP256K1.Signature.create(
+ new BigInteger(
+ "32886959230931919120748662916110619501838190146643992583529828535682419954515"),
+ new BigInteger(
+ "14473701025599600909210599917245952381483216609124029382871721729679842002948"),
+ Byte.valueOf("0")),
+ BytesValue.fromHexString(TRANSACTION_KEY_HEX),
+ Address.wrap(BytesValue.fromHexString("0x8411b12666f68ef74cace3615c9d5a377729d03f")),
+ 1);
+
+ Orion mockOrion() throws IOException {
+ Orion mockOrion = mock(Orion.class);
+ SendResponse response = new SendResponse();
+ response.setKey(TRANSACTION_KEY);
+ when(mockOrion.send(any(SendRequest.class))).thenReturn(response);
+ return mockOrion;
+ }
+
+ Orion brokenMockOrion() throws IOException {
+ Orion mockOrion = mock(Orion.class);
+ when(mockOrion.send(any(SendRequest.class))).thenThrow(IOException.class);
+ return mockOrion;
+ }
+
+ @Before
+ public void setUp() throws IOException {
+ privateTransactionHandler = new PrivateTransactionHandler(mockOrion(), Address.DEFAULT_PRIVACY);
+ brokenPrivateTransactionHandler =
+ new PrivateTransactionHandler(brokenMockOrion(), Address.DEFAULT_PRIVACY);
+ }
+
+ @Test
+ public void validTransactionThroughHandler() throws IOException {
+ final Transaction transactionRespose =
+ privateTransactionHandler.handle(VALID_PRIVATE_TRANSACTION);
+
+ assertThat(transactionRespose).isEqualToComparingFieldByField(PUBLIC_TRANSACTION);
+ }
+
+ @Test(expected = IOException.class)
+ public void enclaveIsDownWhileHandling() throws IOException {
+ brokenPrivateTransactionHandler.handle(VALID_PRIVATE_TRANSACTION);
+ }
+}
diff --git a/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcTestMethodsFactory.java b/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcTestMethodsFactory.java
index b252a6848f..6cbb07ba2d 100644
--- a/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcTestMethodsFactory.java
+++ b/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcTestMethodsFactory.java
@@ -35,6 +35,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpec;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.permissioning.AccountWhitelistController;
+import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionHandler;
import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive;
import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem;
@@ -81,6 +82,8 @@ public class JsonRpcTestMethodsFactory {
final MetricsSystem metricsSystem = new NoOpMetricsSystem();
final AccountWhitelistController accountWhitelistController =
mock(AccountWhitelistController.class);
+ final PrivateTransactionHandler privateTransactionHandler =
+ mock(PrivateTransactionHandler.class);
return new JsonRpcMethodsFactory()
.methods(
@@ -95,6 +98,7 @@ public class JsonRpcTestMethodsFactory {
metricsSystem,
new HashSet<>(),
accountWhitelistController,
- RpcApis.DEFAULT_JSON_RPC_APIS);
+ RpcApis.DEFAULT_JSON_RPC_APIS,
+ privateTransactionHandler);
}
}
diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java
index 79e068f3e8..cf19af1eca 100644
--- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java
+++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java
@@ -85,6 +85,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.wire.Capability;
import tech.pegasys.pantheon.ethereum.permissioning.AccountWhitelistController;
+import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionHandler;
import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive;
import tech.pegasys.pantheon.metrics.MetricsSystem;
@@ -111,7 +112,8 @@ public class JsonRpcMethodsFactory {
final Set supportedCapabilities,
final Collection rpcApis,
final FilterManager filterManager,
- final AccountWhitelistController accountsWhitelistController) {
+ final AccountWhitelistController accountsWhitelistController,
+ final PrivateTransactionHandler privateTransactionHandler) {
final BlockchainQueries blockchainQueries =
new BlockchainQueries(blockchain, worldStateArchive);
return methods(
@@ -126,7 +128,8 @@ public class JsonRpcMethodsFactory {
metricsSystem,
supportedCapabilities,
accountsWhitelistController,
- rpcApis);
+ rpcApis,
+ privateTransactionHandler);
}
public Map methods(
@@ -141,7 +144,8 @@ public class JsonRpcMethodsFactory {
final MetricsSystem metricsSystem,
final Set supportedCapabilities,
final AccountWhitelistController accountsWhitelistController,
- final Collection rpcApis) {
+ final Collection rpcApis,
+ final PrivateTransactionHandler privateTransactionHandler) {
final Map enabledMethods = new HashMap<>();
// @formatter:off
if (rpcApis.contains(RpcApis.ETH)) {
@@ -249,7 +253,9 @@ public class JsonRpcMethodsFactory {
new PermRemoveAccountsFromWhitelist(accountsWhitelistController, parameter));
}
if (rpcApis.contains(RpcApis.EEA)) {
- addMethods(enabledMethods, new EeaSendRawTransaction(transactionPool, parameter));
+ addMethods(
+ enabledMethods,
+ new EeaSendRawTransaction(privateTransactionHandler, transactionPool, parameter));
}
// @formatter:off
return enabledMethods;
diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/EeaSendRawTransaction.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/EeaSendRawTransaction.java
index d22a47289c..61a0bb4a28 100644
--- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/EeaSendRawTransaction.java
+++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/EeaSendRawTransaction.java
@@ -26,10 +26,14 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse;
import tech.pegasys.pantheon.ethereum.mainnet.TransactionValidator.TransactionInvalidReason;
import tech.pegasys.pantheon.ethereum.mainnet.ValidationResult;
+import tech.pegasys.pantheon.ethereum.privacy.PrivateTransaction;
+import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionHandler;
import tech.pegasys.pantheon.ethereum.rlp.RLP;
import tech.pegasys.pantheon.ethereum.rlp.RLPException;
import tech.pegasys.pantheon.util.bytes.BytesValue;
+import java.io.IOException;
+
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -37,11 +41,15 @@ public class EeaSendRawTransaction implements JsonRpcMethod {
private static final Logger LOG = LogManager.getLogger();
+ private final PrivateTransactionHandler privateTransactionHandler;
private final TransactionPool transactionPool;
private final JsonRpcParameter parameters;
public EeaSendRawTransaction(
- final TransactionPool transactionPool, final JsonRpcParameter parameters) {
+ final PrivateTransactionHandler privateTransactionHandler,
+ final TransactionPool transactionPool,
+ final JsonRpcParameter parameters) {
+ this.privateTransactionHandler = privateTransactionHandler;
this.transactionPool = transactionPool;
this.parameters = parameters;
}
@@ -58,13 +66,20 @@ public class EeaSendRawTransaction implements JsonRpcMethod {
}
final String rawPrivateTransaction = parameters.required(request.getParams(), 0, String.class);
- final Transaction transaction;
+ final PrivateTransaction privateTransaction;
try {
- transaction = decodeRawTransaction(rawPrivateTransaction);
+ privateTransaction = decodeRawTransaction(rawPrivateTransaction);
} catch (final InvalidJsonRpcRequestException e) {
return new JsonRpcErrorResponse(request.getId(), JsonRpcError.INVALID_PARAMS);
}
+ final Transaction transaction;
+ try {
+ transaction = handlePrivateTransaction(privateTransaction);
+ } catch (final InvalidJsonRpcRequestException e) {
+ return new JsonRpcErrorResponse(request.getId(), JsonRpcError.ENCLAVE_IS_DOWN);
+ }
+
final ValidationResult validationResult =
transactionPool.addLocalTransaction(transaction);
return validationResult.either(
@@ -74,10 +89,20 @@ public class EeaSendRawTransaction implements JsonRpcMethod {
request.getId(), convertTransactionInvalidReason(errorReason)));
}
- private Transaction decodeRawTransaction(final String hash)
+ private Transaction handlePrivateTransaction(final PrivateTransaction privateTransaction)
+ throws InvalidJsonRpcRequestException {
+ try {
+ return privateTransactionHandler.handle(privateTransaction);
+ } catch (final IOException e) {
+ LOG.debug(e);
+ throw new InvalidJsonRpcRequestException("Unable to handle private transaction", e);
+ }
+ }
+
+ private PrivateTransaction decodeRawTransaction(final String hash)
throws InvalidJsonRpcRequestException {
try {
- return Transaction.readFrom(RLP.input(BytesValue.fromHexString(hash)));
+ return PrivateTransaction.readFrom(RLP.input(BytesValue.fromHexString(hash)));
} catch (final IllegalArgumentException | RLPException e) {
LOG.debug(e);
throw new InvalidJsonRpcRequestException("Invalid raw private transaction hex", e);
diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/response/JsonRpcError.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/response/JsonRpcError.java
index 70d855ba8c..c70b4d9117 100644
--- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/response/JsonRpcError.java
+++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/response/JsonRpcError.java
@@ -61,7 +61,10 @@ public enum JsonRpcError {
NODE_WHITELIST_DUPLICATED_ENTRY(-32000, "Request can't contain duplicated node entries"),
NODE_WHITELIST_EXISTING_ENTRY(-32000, "Node whitelist can't contain duplicated node entries"),
NODE_WHITELIST_MISSING_ENTRY(-32000, "Node whitelist does not contain a specified node"),
- NODE_WHITELIST_INVALID_ENTRY(-32000, "Unable to add invalid node to the node whitelist");
+ NODE_WHITELIST_INVALID_ENTRY(-32000, "Unable to add invalid node to the node whitelist"),
+
+ // Private transaction errors
+ ENCLAVE_IS_DOWN(-32000, "Enclave is down");
private final int code;
private final String message;
diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractEthJsonRpcHttpServiceTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractEthJsonRpcHttpServiceTest.java
index c259fd5cf0..62c18f881e 100644
--- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractEthJsonRpcHttpServiceTest.java
+++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractEthJsonRpcHttpServiceTest.java
@@ -47,6 +47,7 @@ import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.wire.Capability;
import tech.pegasys.pantheon.ethereum.permissioning.AccountWhitelistController;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
+import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionHandler;
import tech.pegasys.pantheon.ethereum.util.RawBlockIterator;
import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive;
import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem;
@@ -149,6 +150,8 @@ public abstract class AbstractEthJsonRpcHttpServiceTest {
.thenReturn(ValidationResult.valid());
final PendingTransactions pendingTransactionsMock = mock(PendingTransactions.class);
when(transactionPoolMock.getPendingTransactions()).thenReturn(pendingTransactionsMock);
+ final PrivateTransactionHandler privateTransactionHandlerMock =
+ mock(PrivateTransactionHandler.class);
stateArchive = createInMemoryWorldStateArchive();
GENESIS_CONFIG.writeStateTo(stateArchive.getMutable(Hash.EMPTY_TRIE_HASH));
@@ -184,7 +187,8 @@ public abstract class AbstractEthJsonRpcHttpServiceTest {
new NoOpMetricsSystem(),
supportedCapabilities,
accountWhitelistController,
- JSON_RPC_APIS);
+ JSON_RPC_APIS,
+ privateTransactionHandlerMock);
final JsonRpcConfiguration config = JsonRpcConfiguration.createDefault();
config.setPort(0);
service =
diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceHostWhitelistTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceHostWhitelistTest.java
index e61261ac32..cc65a02f49 100644
--- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceHostWhitelistTest.java
+++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceHostWhitelistTest.java
@@ -29,6 +29,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSchedule;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.wire.Capability;
import tech.pegasys.pantheon.ethereum.permissioning.AccountWhitelistController;
+import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionHandler;
import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem;
import java.io.IOException;
@@ -97,7 +98,8 @@ public class JsonRpcHttpServiceHostWhitelistTest {
new NoOpMetricsSystem(),
supportedCapabilities,
mock(AccountWhitelistController.class),
- JSON_RPC_APIS));
+ JSON_RPC_APIS,
+ mock(PrivateTransactionHandler.class)));
service = createJsonRpcHttpService();
service.start().join();
diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceRpcApisTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceRpcApisTest.java
index 0a6aa1a6b7..89b149398e 100644
--- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceRpcApisTest.java
+++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceRpcApisTest.java
@@ -29,6 +29,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSchedule;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.wire.Capability;
import tech.pegasys.pantheon.ethereum.permissioning.AccountWhitelistController;
+import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionHandler;
import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem;
import java.util.HashSet;
@@ -177,7 +178,8 @@ public class JsonRpcHttpServiceRpcApisTest {
new NoOpMetricsSystem(),
supportedCapabilities,
mock(AccountWhitelistController.class),
- config.getRpcApis()));
+ config.getRpcApis(),
+ mock(PrivateTransactionHandler.class)));
final JsonRpcHttpService jsonRpcHttpService =
new JsonRpcHttpService(
vertx, folder.newFolder().toPath(), config, new NoOpMetricsSystem(), rpcMethods);
diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceTest.java
index f4a3ae2411..eb67f2716e 100644
--- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceTest.java
+++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceTest.java
@@ -44,6 +44,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSchedule;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.wire.Capability;
import tech.pegasys.pantheon.ethereum.permissioning.AccountWhitelistController;
+import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionHandler;
import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import tech.pegasys.pantheon.util.bytes.BytesValues;
@@ -126,7 +127,8 @@ public class JsonRpcHttpServiceTest {
new NoOpMetricsSystem(),
supportedCapabilities,
mock(AccountWhitelistController.class),
- JSON_RPC_APIS));
+ JSON_RPC_APIS,
+ mock(PrivateTransactionHandler.class)));
service = createJsonRpcHttpService();
service.start().join();
diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/EeaSendRawTransactionTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/EeaSendRawTransactionTest.java
index 72dfcf2ca6..6780b21a8a 100644
--- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/EeaSendRawTransactionTest.java
+++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/EeaSendRawTransactionTest.java
@@ -18,8 +18,11 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import tech.pegasys.pantheon.crypto.SECP256K1;
+import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.Transaction;
import tech.pegasys.pantheon.ethereum.core.TransactionPool;
+import tech.pegasys.pantheon.ethereum.core.Wei;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcError;
@@ -28,6 +31,13 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse;
import tech.pegasys.pantheon.ethereum.mainnet.TransactionValidator.TransactionInvalidReason;
import tech.pegasys.pantheon.ethereum.mainnet.ValidationResult;
+import tech.pegasys.pantheon.ethereum.privacy.PrivateTransaction;
+import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionHandler;
+import tech.pegasys.pantheon.util.bytes.BytesValue;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
@@ -38,17 +48,49 @@ import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class EeaSendRawTransactionTest {
- private static final String VALID_TRANSACTION =
- "0xf86d0485174876e800830222e0945aae326516b4f8fe08074b7e972e40a713048d62880de0b6b3a7640000801ba05d4e7998757264daab67df2ce6f7e7a0ae36910778a406ca73898c9899a32b9ea0674700d5c3d1d27f2e6b4469957dfd1a1c49bf92383d80717afc84eb05695d5b";
+ private static final String VALID_PRIVATE_TRANSACTION_RLP =
+ "0xf90113800182520894095e7baea6a6c7c4c2dfeb977efac326af552d87"
+ + "a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ + "ffff801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d"
+ + "495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab94"
+ + "9f53faa07bd2c804ac41316156744d784c4355486d425648586f5a7a7a4267"
+ + "5062572f776a3561784470573958386c393153476f3df85aac41316156744d"
+ + "784c4355486d425648586f5a7a7a42675062572f776a356178447057395838"
+ + "6c393153476f3dac4b6f32625671442b6e4e6c4e594c35454537793349644f"
+ + "6e766966746a69697a706a52742b4854754642733d8a726573747269637465"
+ + "64";
+
+ private static final Transaction PUBLIC_TRANSACTION =
+ new Transaction(
+ 0L,
+ Wei.of(1),
+ 21000L,
+ Optional.of(
+ Address.wrap(BytesValue.fromHexString("0x095e7baea6a6c7c4c2dfeb977efac326af552d87"))),
+ Wei.of(
+ new BigInteger(
+ "115792089237316195423570985008687907853269984665640564039457584007913129639935")),
+ SECP256K1.Signature.create(
+ new BigInteger(
+ "32886959230931919120748662916110619501838190146643992583529828535682419954515"),
+ new BigInteger(
+ "14473701025599600909210599917245952381483216609124029382871721729679842002948"),
+ Byte.valueOf("0")),
+ BytesValue.fromHexString("0x"),
+ Address.wrap(BytesValue.fromHexString("0x8411b12666f68ef74cace3615c9d5a377729d03f")),
+ 0);
+
@Mock private TransactionPool transactionPool;
@Mock private JsonRpcParameter parameter;
- private EeaSendRawTransaction method;
+ @Mock private EeaSendRawTransaction method;
+
+ @Mock private PrivateTransactionHandler privateTxHandler;
@Before
public void before() {
- method = new EeaSendRawTransaction(transactionPool, parameter);
+ method = new EeaSendRawTransaction(privateTxHandler, transactionPool, parameter);
}
@Test
@@ -81,76 +123,84 @@ public class EeaSendRawTransactionTest {
}
@Test
- public void validTransactionIsSentToTransactionPool() {
- when(parameter.required(any(Object[].class), anyInt(), any())).thenReturn(VALID_TRANSACTION);
+ public void validTransactionIsSentToTransactionPool() throws IOException {
+ when(parameter.required(any(Object[].class), anyInt(), any()))
+ .thenReturn(VALID_PRIVATE_TRANSACTION_RLP);
+ when(privateTxHandler.handle(any(PrivateTransaction.class))).thenReturn(PUBLIC_TRANSACTION);
when(transactionPool.addLocalTransaction(any(Transaction.class)))
.thenReturn(ValidationResult.valid());
final JsonRpcRequest request =
- new JsonRpcRequest("2.0", "eea_sendRawTransaction", new String[] {VALID_TRANSACTION});
+ new JsonRpcRequest(
+ "2.0", "eea_sendRawTransaction", new String[] {VALID_PRIVATE_TRANSACTION_RLP});
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(
- request.getId(), "0xbaabcc1bd699e7378451e4ce5969edb9bdcae76cb79bdacae793525c31e423c7");
+ request.getId(), "0xa86e8a2324e3abccd52afd6913c4c8a5d91f5d1855c0aa075568416c0a3ff7b2");
final JsonRpcResponse actualResponse = method.response(request);
assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse);
+ verify(privateTxHandler).handle(any(PrivateTransaction.class));
verify(transactionPool).addLocalTransaction(any(Transaction.class));
}
@Test
- public void transactionWithNonceBelowAccountNonceIsRejected() {
+ public void transactionWithNonceBelowAccountNonceIsRejected() throws IOException {
verifyErrorForInvalidTransaction(
TransactionInvalidReason.NONCE_TOO_LOW, JsonRpcError.NONCE_TOO_LOW);
}
@Test
- public void transactionWithNonceAboveAccountNonceIsRejected() {
+ public void transactionWithNonceAboveAccountNonceIsRejected() throws IOException {
verifyErrorForInvalidTransaction(
TransactionInvalidReason.INCORRECT_NONCE, JsonRpcError.INCORRECT_NONCE);
}
@Test
- public void transactionWithInvalidSignatureIsRejected() {
+ public void transactionWithInvalidSignatureIsRejected() throws IOException {
verifyErrorForInvalidTransaction(
TransactionInvalidReason.INVALID_SIGNATURE, JsonRpcError.INVALID_TRANSACTION_SIGNATURE);
}
@Test
- public void transactionWithIntrinsicGasExceedingGasLimitIsRejected() {
+ public void transactionWithIntrinsicGasExceedingGasLimitIsRejected() throws IOException {
verifyErrorForInvalidTransaction(
TransactionInvalidReason.INTRINSIC_GAS_EXCEEDS_GAS_LIMIT,
JsonRpcError.INTRINSIC_GAS_EXCEEDS_LIMIT);
}
@Test
- public void transactionWithUpfrontGasExceedingAccountBalanceIsRejected() {
+ public void transactionWithUpfrontGasExceedingAccountBalanceIsRejected() throws IOException {
verifyErrorForInvalidTransaction(
TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE,
JsonRpcError.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE);
}
@Test
- public void transactionWithGasLimitExceedingBlockGasLimitIsRejected() {
+ public void transactionWithGasLimitExceedingBlockGasLimitIsRejected() throws IOException {
verifyErrorForInvalidTransaction(
TransactionInvalidReason.EXCEEDS_BLOCK_GAS_LIMIT, JsonRpcError.EXCEEDS_BLOCK_GAS_LIMIT);
}
@Test
- public void transactionWithNotWhitelistedSenderAccountIsRejected() {
+ public void transactionWithNotWhitelistedSenderAccountIsRejected() throws IOException {
verifyErrorForInvalidTransaction(
TransactionInvalidReason.TX_SENDER_NOT_AUTHORIZED, JsonRpcError.TX_SENDER_NOT_AUTHORIZED);
}
private void verifyErrorForInvalidTransaction(
- final TransactionInvalidReason transactionInvalidReason, final JsonRpcError expectedError) {
- when(parameter.required(any(Object[].class), anyInt(), any())).thenReturn(VALID_TRANSACTION);
+ final TransactionInvalidReason transactionInvalidReason, final JsonRpcError expectedError)
+ throws IOException {
+ when(parameter.required(any(Object[].class), anyInt(), any()))
+ .thenReturn(VALID_PRIVATE_TRANSACTION_RLP);
+ when(privateTxHandler.handle(any(PrivateTransaction.class))).thenReturn(PUBLIC_TRANSACTION);
when(transactionPool.addLocalTransaction(any(Transaction.class)))
.thenReturn(ValidationResult.invalid(transactionInvalidReason));
final JsonRpcRequest request =
- new JsonRpcRequest("2.0", "eea_sendRawTransaction", new String[] {VALID_TRANSACTION});
+ new JsonRpcRequest(
+ "2.0", "eea_sendRawTransaction", new String[] {VALID_PRIVATE_TRANSACTION_RLP});
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(request.getId(), expectedError);
@@ -158,6 +208,7 @@ public class EeaSendRawTransactionTest {
final JsonRpcResponse actualResponse = method.response(request);
assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse);
+ verify(privateTxHandler).handle(any(PrivateTransaction.class));
verify(transactionPool).addLocalTransaction(any(Transaction.class));
}
diff --git a/orion/src/integration-test/java/tech/pegasys/pantheon/orion/OrionTest.java b/orion/src/integration-test/java/tech/pegasys/pantheon/orion/OrionTest.java
index 420ca2f395..c73514ea3f 100644
--- a/orion/src/integration-test/java/tech/pegasys/pantheon/orion/OrionTest.java
+++ b/orion/src/integration-test/java/tech/pegasys/pantheon/orion/OrionTest.java
@@ -25,6 +25,7 @@ import tech.pegasys.pantheon.orion.types.SendResponse;
import java.io.IOException;
import java.util.List;
+import com.google.common.collect.Lists;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.ClassRule;
@@ -63,7 +64,8 @@ public class OrionTest {
public void testSendAndReceive() throws IOException {
List publicKeys = testHarness.getPublicKeys();
- SendRequest sc = new SendRequest(PAYLOAD, publicKeys.get(0), new String[] {publicKeys.get(1)});
+ SendRequest sc =
+ new SendRequest(PAYLOAD, publicKeys.get(0), Lists.newArrayList(publicKeys.get(1)));
SendResponse sr = orion.send(sc);
ReceiveRequest rc = new ReceiveRequest(sr.getKey(), publicKeys.get(1));
diff --git a/orion/src/main/java/tech/pegasys/pantheon/orion/types/SendRequest.java b/orion/src/main/java/tech/pegasys/pantheon/orion/types/SendRequest.java
index afbf3bc474..9d20d84b7e 100644
--- a/orion/src/main/java/tech/pegasys/pantheon/orion/types/SendRequest.java
+++ b/orion/src/main/java/tech/pegasys/pantheon/orion/types/SendRequest.java
@@ -14,12 +14,14 @@ package tech.pegasys.pantheon.orion.types;
import static java.nio.charset.StandardCharsets.UTF_8;
+import java.util.List;
+
public class SendRequest {
private byte[] payload;
private String from;
- private String[] to;
+ private List to;
- public SendRequest(final String payload, final String from, final String[] to) {
+ public SendRequest(final String payload, final String from, final List to) {
this.payload = payload.getBytes(UTF_8);
this.from = from;
this.to = to;
@@ -41,11 +43,11 @@ public class SendRequest {
this.from = from;
}
- public String[] getTo() {
+ public List getTo() {
return to;
}
- public void setTo(final String[] to) {
+ public void setTo(final List to) {
this.to = to;
}
}
diff --git a/pantheon/build.gradle b/pantheon/build.gradle
index fd04cbe468..0941f54a77 100644
--- a/pantheon/build.gradle
+++ b/pantheon/build.gradle
@@ -40,6 +40,7 @@ dependencies {
implementation project(':ethereum:p2p')
implementation project(':ethereum:rlp')
implementation project(':metrics')
+ implementation project(':orion')
implementation project(':services:kvstore')
implementation 'com.google.guava:guava'
diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java b/pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java
index 32c32f7b0c..fd6bd3d040 100644
--- a/pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java
+++ b/pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java
@@ -17,6 +17,7 @@ import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.blockcreation.MiningCoordinator;
import tech.pegasys.pantheon.ethereum.chain.Blockchain;
+import tech.pegasys.pantheon.ethereum.core.PrivacyParameters;
import tech.pegasys.pantheon.ethereum.core.Synchronizer;
import tech.pegasys.pantheon.ethereum.core.TransactionPool;
import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration;
@@ -53,6 +54,7 @@ import tech.pegasys.pantheon.ethereum.p2p.wire.Capability;
import tech.pegasys.pantheon.ethereum.p2p.wire.SubProtocol;
import tech.pegasys.pantheon.ethereum.permissioning.AccountWhitelistController;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
+import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionHandler;
import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive;
import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.metrics.prometheus.MetricsConfiguration;
@@ -239,13 +241,16 @@ public class RunnerBuilder {
final TransactionPool transactionPool = pantheonController.getTransactionPool();
final MiningCoordinator miningCoordinator = pantheonController.getMiningCoordinator();
-
final AccountWhitelistController accountWhitelistController =
new AccountWhitelistController(permissioningConfiguration);
if (permissioningConfiguration.isAccountWhitelistSet()) {
transactionPool.setAccountWhitelist(accountWhitelistController);
}
+ final PrivacyParameters privacyParameters = pantheonController.getPrivacyParameters();
+ final PrivateTransactionHandler privateTransactionHandler =
+ new PrivateTransactionHandler(privacyParameters);
+
final FilterManager filterManager = createFilterManager(vertx, context, transactionPool);
Optional jsonRpcHttpService = Optional.empty();
@@ -263,7 +268,8 @@ public class RunnerBuilder {
supportedCapabilities,
jsonRpcConfiguration.getRpcApis(),
filterManager,
- accountWhitelistController);
+ accountWhitelistController,
+ privateTransactionHandler);
jsonRpcHttpService =
Optional.of(
new JsonRpcHttpService(
@@ -285,7 +291,8 @@ public class RunnerBuilder {
supportedCapabilities,
webSocketConfiguration.getRpcApis(),
filterManager,
- accountWhitelistController);
+ accountWhitelistController,
+ privateTransactionHandler);
final SubscriptionManager subscriptionManager =
createSubscriptionManager(
@@ -344,7 +351,8 @@ public class RunnerBuilder {
final Set supportedCapabilities,
final Collection jsonRpcApis,
final FilterManager filterManager,
- final AccountWhitelistController accountWhitelistController) {
+ final AccountWhitelistController accountWhitelistController,
+ final PrivateTransactionHandler privateTransactionHandler) {
final Map methods =
new JsonRpcMethodsFactory()
.methods(
@@ -360,7 +368,8 @@ public class RunnerBuilder {
supportedCapabilities,
jsonRpcApis,
filterManager,
- accountWhitelistController);
+ accountWhitelistController,
+ privateTransactionHandler);
methods.putAll(pantheonController.getAdditionalJsonRpcMethods(jsonRpcApis));
return methods;
}
diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java
index d3139fd300..1d36950f38 100644
--- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java
+++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java
@@ -38,6 +38,7 @@ import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.ethereum.core.MiningParameters;
+import tech.pegasys.pantheon.ethereum.core.PrivacyParameters;
import tech.pegasys.pantheon.ethereum.core.Synchronizer;
import tech.pegasys.pantheon.ethereum.core.TransactionPool;
import tech.pegasys.pantheon.ethereum.core.Util;
@@ -254,6 +255,12 @@ public class CliquePantheonController implements PantheonController getAdditionalJsonRpcMethods(
final Collection enabledRpcApis) {
diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftLegacyPantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftLegacyPantheonController.java
index d93a1f1453..94b498a778 100644
--- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftLegacyPantheonController.java
+++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftLegacyPantheonController.java
@@ -35,6 +35,7 @@ import tech.pegasys.pantheon.ethereum.chain.DefaultMutableBlockchain;
import tech.pegasys.pantheon.ethereum.chain.GenesisState;
import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain;
import tech.pegasys.pantheon.ethereum.core.Hash;
+import tech.pegasys.pantheon.ethereum.core.PrivacyParameters;
import tech.pegasys.pantheon.ethereum.core.Synchronizer;
import tech.pegasys.pantheon.ethereum.core.TransactionPool;
import tech.pegasys.pantheon.ethereum.eth.EthProtocol;
@@ -235,6 +236,12 @@ public class IbftLegacyPantheonController implements PantheonController getAdditionalJsonRpcMethods(
final Collection enabledRpcApis) {
diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonController.java
index 18d7288bcd..c6ac82bf41 100644
--- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonController.java
+++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonController.java
@@ -54,6 +54,7 @@ import tech.pegasys.pantheon.ethereum.chain.MinedBlockObserver;
import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain;
import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.ethereum.core.MiningParameters;
+import tech.pegasys.pantheon.ethereum.core.PrivacyParameters;
import tech.pegasys.pantheon.ethereum.core.Synchronizer;
import tech.pegasys.pantheon.ethereum.core.TransactionPool;
import tech.pegasys.pantheon.ethereum.core.Util;
@@ -322,6 +323,12 @@ public class IbftPantheonController implements PantheonController {
return null;
}
+ @Override
+ public PrivacyParameters getPrivacyParameters() {
+ LOG.warn("IbftPantheonController does not currently support private transactions.");
+ return PrivacyParameters.noPrivacy();
+ }
+
@Override
public Map getAdditionalJsonRpcMethods(
final Collection enabledRpcApis) {
diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java
index 2ee0c7a352..98efccaac3 100644
--- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java
+++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java
@@ -25,6 +25,7 @@ import tech.pegasys.pantheon.ethereum.chain.GenesisState;
import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain;
import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.ethereum.core.MiningParameters;
+import tech.pegasys.pantheon.ethereum.core.PrivacyParameters;
import tech.pegasys.pantheon.ethereum.core.Synchronizer;
import tech.pegasys.pantheon.ethereum.core.TransactionPool;
import tech.pegasys.pantheon.ethereum.eth.EthProtocol;
@@ -66,6 +67,7 @@ public class MainnetPantheonController implements PantheonController {
private final TransactionPool transactionPool;
private final MiningCoordinator miningCoordinator;
+ private final PrivacyParameters privacyParameters;
private final Runnable close;
public MainnetPantheonController(
@@ -76,6 +78,7 @@ public class MainnetPantheonController implements PantheonController {
final KeyPair keyPair,
final TransactionPool transactionPool,
final MiningCoordinator miningCoordinator,
+ final PrivacyParameters privacyParameters,
final Runnable close) {
this.protocolSchedule = protocolSchedule;
this.protocolContext = protocolContext;
@@ -84,6 +87,7 @@ public class MainnetPantheonController implements PantheonController {
this.keyPair = keyPair;
this.transactionPool = transactionPool;
this.miningCoordinator = miningCoordinator;
+ this.privacyParameters = privacyParameters;
this.close = close;
}
@@ -94,7 +98,8 @@ public class MainnetPantheonController implements PantheonController {
final SynchronizerConfiguration taintedSyncConfig,
final MiningParameters miningParams,
final KeyPair nodeKeys,
- final MetricsSystem metricsSystem) {
+ final MetricsSystem metricsSystem,
+ final PrivacyParameters privacyParameters) {
final GenesisState genesisState = GenesisState.fromConfig(genesisConfig, protocolSchedule);
final BlockchainStorage blockchainStorage =
@@ -168,6 +173,7 @@ public class MainnetPantheonController implements PantheonController {
nodeKeys,
transactionPool,
miningCoordinator,
+ privacyParameters,
() -> {
miningCoordinator.disable();
minerThreadPool.shutdownNow();
@@ -223,4 +229,9 @@ public class MainnetPantheonController implements PantheonController {
public void close() {
close.run();
}
+
+ @Override
+ public PrivacyParameters getPrivacyParameters() {
+ return privacyParameters;
+ }
}
diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java
index b8d251889f..21c556ed0d 100644
--- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java
+++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java
@@ -61,7 +61,8 @@ public interface PantheonController extends Closeable {
syncConfig,
miningParameters,
nodeKeys,
- metricsSystem);
+ metricsSystem,
+ privacyParameters);
} else if (configOptions.isRevisedIbft()) {
return IbftPantheonController.init(
storageProvider,
@@ -108,6 +109,8 @@ public interface PantheonController extends Closeable {
MiningCoordinator getMiningCoordinator();
+ PrivacyParameters getPrivacyParameters();
+
default Map getAdditionalJsonRpcMethods(
final Collection enabledRpcApis) {
return emptyMap();
diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java
index a8dad2c2bf..f66e272520 100644
--- a/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java
+++ b/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java
@@ -25,6 +25,7 @@ import tech.pegasys.pantheon.ethereum.core.BlockImporter;
import tech.pegasys.pantheon.ethereum.core.BlockSyncTestUtils;
import tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider;
import tech.pegasys.pantheon.ethereum.core.MiningParametersTestBuilder;
+import tech.pegasys.pantheon.ethereum.core.PrivacyParameters;
import tech.pegasys.pantheon.ethereum.eth.sync.SyncMode;
import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration;
import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration;
@@ -109,7 +110,8 @@ public final class RunnerTest {
fastSyncConfig,
new MiningParametersTestBuilder().enabled(false).build(),
aheadDbNodeKeys,
- noOpMetricsSystem)) {
+ noOpMetricsSystem,
+ PrivacyParameters.noPrivacy())) {
setupState(blockCount, controller.getProtocolSchedule(), controller.getProtocolContext());
}
@@ -122,7 +124,8 @@ public final class RunnerTest {
fastSyncConfig,
new MiningParametersTestBuilder().enabled(false).build(),
aheadDbNodeKeys,
- noOpMetricsSystem);
+ noOpMetricsSystem,
+ PrivacyParameters.noPrivacy());
final String listenHost = InetAddress.getLoopbackAddress().getHostAddress();
final ExecutorService executorService = Executors.newFixedThreadPool(2);
final JsonRpcConfiguration aheadJsonRpcConfiguration = jsonRpcConfiguration();
@@ -165,7 +168,8 @@ public final class RunnerTest {
fastSyncConfig,
new MiningParametersTestBuilder().enabled(false).build(),
KeyPair.generate(),
- noOpMetricsSystem);
+ noOpMetricsSystem,
+ PrivacyParameters.noPrivacy());
final Runner runnerBehind =
runnerBuilder
.pantheonController(controllerBehind)