From f2438dcf79e1834120975757b9ead38260cab528 Mon Sep 17 00:00:00 2001 From: Vinicius Stevam <45455812+vinistevam@users.noreply.github.com> Date: Thu, 31 Jan 2019 09:22:17 +0000 Subject: [PATCH] [PRIV] Private Transaction Handler (#695) * Add PrivateTransactionHandler * Implementing PrivateTransactionHandler * Send Privacy Marker Transaction to Privacy Precompile Smart Contract * Tests Handler * Fix up Private Transaction Handler Test * Remove wildcard import * Remove Orion tests from PrivateTransactionHandler * Fix test exception * Return error if orion call fails * Fix PrivateTransactionHandler implementation - The whole base64 rlp encoded private transaction should be sent to Orion rather than the base64 encoded input of the private transaction. Signed-off-by: Adrian Sutton --- .../pantheon/ethereum/core/Transaction.java | 2 +- .../privacy/PrivateTransactionHandler.java | 91 +++++++++++++ .../PrivateTransactionHandlerTest.java | 126 ++++++++++++++++++ .../jsonrpc/JsonRpcTestMethodsFactory.java | 6 +- .../jsonrpc/JsonRpcMethodsFactory.java | 14 +- .../privacy/EeaSendRawTransaction.java | 35 ++++- .../internal/response/JsonRpcError.java | 5 +- .../AbstractEthJsonRpcHttpServiceTest.java | 6 +- .../JsonRpcHttpServiceHostWhitelistTest.java | 4 +- .../JsonRpcHttpServiceRpcApisTest.java | 4 +- .../jsonrpc/JsonRpcHttpServiceTest.java | 4 +- .../privacy/EeaSendRawTransactionTest.java | 87 +++++++++--- .../pegasys/pantheon/orion/OrionTest.java | 4 +- .../pantheon/orion/types/SendRequest.java | 10 +- pantheon/build.gradle | 1 + .../tech/pegasys/pantheon/RunnerBuilder.java | 19 ++- .../controller/CliquePantheonController.java | 7 + .../IbftLegacyPantheonController.java | 7 + .../controller/IbftPantheonController.java | 7 + .../controller/MainnetPantheonController.java | 13 +- .../controller/PantheonController.java | 5 +- .../tech/pegasys/pantheon/RunnerTest.java | 10 +- 22 files changed, 418 insertions(+), 49 deletions(-) create mode 100644 ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionHandler.java create mode 100644 ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionHandlerTest.java 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)