PrivacyMarkerTransaction to be signed with a randomly generated key (#1844)

Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
Trent Mohay 5 years ago committed by GitHub
parent 407dcbf33d
commit 5df733e83e
  1. 2
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ProcessPantheonNodeRunner.java
  2. 17
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/PrivacyParameters.java
  3. 48
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionHandler.java
  4. 45
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/privacy/markertransaction/FixedKeySigningPrivateMarkerTransactionFactory.java
  5. 50
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/privacy/markertransaction/PrivateMarkerTransactionFactory.java
  6. 32
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/privacy/markertransaction/RandomSigningPrivateMarkerTransactionFactory.java
  7. 21
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/util/NonceProvider.java
  8. 17
      ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionHandlerTest.java
  9. 75
      ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/privacy/markertransaction/FixedKeySigningPrivateMarkerTransactionFactoryTest.java
  10. 67
      ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/privacy/markertransaction/RandomSigningPrivateMarkerTransactionFactoryTest.java
  11. 32
      ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java
  12. 39
      ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/LatestNonceProvider.java
  13. 20
      ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/eea/EeaSendRawTransaction.java
  14. 54
      ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/LatestNonceProviderTest.java
  15. 33
      ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/privacy/eea/EeaSendRawTransactionTest.java
  16. 7
      pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java
  17. 1
      pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonControllerBuilder.java
  18. 1
      pantheon/src/test/resources/everything_config.toml

@ -92,6 +92,8 @@ public class ProcessPantheonNodeRunner implements PantheonNodeRunner {
params.add(node.getPrivacyParameters().getEnclavePublicKeyFile().getAbsolutePath()); params.add(node.getPrivacyParameters().getEnclavePublicKeyFile().getAbsolutePath());
params.add("--privacy-precompiled-address"); params.add("--privacy-precompiled-address");
params.add(String.valueOf(node.getPrivacyParameters().getPrivacyAddress())); params.add(String.valueOf(node.getPrivacyParameters().getPrivacyAddress()));
params.add("--privacy-marker-transaction-signing-key-file");
params.add(node.homeDirectory().resolve("key").toString());
} }
params.add("--bootnodes"); params.add("--bootnodes");

@ -15,6 +15,7 @@ package tech.pegasys.pantheon.ethereum.core;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;
import tech.pegasys.pantheon.crypto.SECP256K1; import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.privacy.PrivateStateStorage; import tech.pegasys.pantheon.ethereum.privacy.PrivateStateStorage;
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionStorage; import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionStorage;
import tech.pegasys.pantheon.ethereum.storage.StorageProvider; import tech.pegasys.pantheon.ethereum.storage.StorageProvider;
@ -30,6 +31,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Optional;
import com.google.common.io.Files; import com.google.common.io.Files;
@ -42,7 +44,7 @@ public class PrivacyParameters {
private URI enclaveUri; private URI enclaveUri;
private String enclavePublicKey; private String enclavePublicKey;
private File enclavePublicKeyFile; private File enclavePublicKeyFile;
private SECP256K1.KeyPair signingKeyPair; private Optional<SECP256K1.KeyPair> signingKeyPair = Optional.empty();
private WorldStateArchive privateWorldStateArchive; private WorldStateArchive privateWorldStateArchive;
private StorageProvider privateStorageProvider; private StorageProvider privateStorageProvider;
@ -89,12 +91,12 @@ public class PrivacyParameters {
this.enclavePublicKeyFile = enclavePublicKeyFile; this.enclavePublicKeyFile = enclavePublicKeyFile;
} }
public SECP256K1.KeyPair getSigningKeyPair() { public Optional<SECP256K1.KeyPair> getSigningKeyPair() {
return signingKeyPair; return signingKeyPair;
} }
public void setSigningKeyPair(final SECP256K1.KeyPair signingKeyPair) { public void setSigningKeyPair(final SECP256K1.KeyPair signingKeyPair) {
this.signingKeyPair = signingKeyPair; this.signingKeyPair = Optional.ofNullable(signingKeyPair);
} }
public WorldStateArchive getPrivateWorldStateArchive() { public WorldStateArchive getPrivateWorldStateArchive() {
@ -145,6 +147,7 @@ public class PrivacyParameters {
private Path dataDir; private Path dataDir;
private File enclavePublicKeyFile; private File enclavePublicKeyFile;
private String enclavePublicKey; private String enclavePublicKey;
private Path privateKeyPath;
public Builder setPrivacyAddress(final Integer privacyAddress) { public Builder setPrivacyAddress(final Integer privacyAddress) {
this.privacyAddress = privacyAddress; this.privacyAddress = privacyAddress;
@ -171,6 +174,11 @@ public class PrivacyParameters {
return this; return this;
} }
public Builder setPrivateKeyPath(final Path privateKeyPath) {
this.privateKeyPath = privateKeyPath;
return this;
}
public PrivacyParameters build() throws IOException { public PrivacyParameters build() throws IOException {
PrivacyParameters config = new PrivacyParameters(); PrivacyParameters config = new PrivacyParameters();
if (enabled) { if (enabled) {
@ -200,6 +208,9 @@ public class PrivacyParameters {
config.setPrivateStorageProvider(privateStorageProvider); config.setPrivateStorageProvider(privateStorageProvider);
config.setPrivateTransactionStorage(privateTransactionStorage); config.setPrivateTransactionStorage(privateTransactionStorage);
config.setPrivateStateStorage(privateStateStorage); config.setPrivateStateStorage(privateStateStorage);
if (privateKeyPath != null) {
config.setSigningKeyPair(KeyPair.load(privateKeyPath.toFile()));
}
} }
config.setEnabled(enabled); config.setEnabled(enabled);
config.setEnclaveUri(enclaveUrl); config.setEnclaveUri(enclaveUrl);

@ -12,7 +12,6 @@
*/ */
package tech.pegasys.pantheon.ethereum.privacy; package tech.pegasys.pantheon.ethereum.privacy;
import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.enclave.Enclave; import tech.pegasys.pantheon.enclave.Enclave;
import tech.pegasys.pantheon.enclave.types.ReceiveRequest; import tech.pegasys.pantheon.enclave.types.ReceiveRequest;
import tech.pegasys.pantheon.enclave.types.ReceiveResponse; import tech.pegasys.pantheon.enclave.types.ReceiveResponse;
@ -24,9 +23,9 @@ import tech.pegasys.pantheon.ethereum.core.Account;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.PrivacyParameters; import tech.pegasys.pantheon.ethereum.core.PrivacyParameters;
import tech.pegasys.pantheon.ethereum.core.Transaction; import tech.pegasys.pantheon.ethereum.core.Transaction;
import tech.pegasys.pantheon.ethereum.core.Util;
import tech.pegasys.pantheon.ethereum.mainnet.TransactionValidator.TransactionInvalidReason; import tech.pegasys.pantheon.ethereum.mainnet.TransactionValidator.TransactionInvalidReason;
import tech.pegasys.pantheon.ethereum.mainnet.ValidationResult; import tech.pegasys.pantheon.ethereum.mainnet.ValidationResult;
import tech.pegasys.pantheon.ethereum.privacy.markertransaction.PrivateMarkerTransactionFactory;
import tech.pegasys.pantheon.ethereum.rlp.BytesValueRLPOutput; import tech.pegasys.pantheon.ethereum.rlp.BytesValueRLPOutput;
import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive; import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive;
import tech.pegasys.pantheon.util.bytes.BytesValues; import tech.pegasys.pantheon.util.bytes.BytesValues;
@ -44,42 +43,38 @@ public class PrivateTransactionHandler {
private static final Logger LOG = LogManager.getLogger(); private static final Logger LOG = LogManager.getLogger();
private final Enclave enclave; private final Enclave enclave;
private final Address privacyPrecompileAddress;
private final SECP256K1.KeyPair nodeKeyPair;
private final Address signerAddress;
private final String enclavePublicKey; private final String enclavePublicKey;
private final PrivateStateStorage privateStateStorage; private final PrivateStateStorage privateStateStorage;
private final WorldStateArchive privateWorldStateArchive; private final WorldStateArchive privateWorldStateArchive;
private final PrivateTransactionValidator privateTransactionValidator; private final PrivateTransactionValidator privateTransactionValidator;
private final PrivateMarkerTransactionFactory privateMarkerTransactionFactory;
public PrivateTransactionHandler( public PrivateTransactionHandler(
final PrivacyParameters privacyParameters, final Optional<BigInteger> chainId) { final PrivacyParameters privacyParameters,
final Optional<BigInteger> chainId,
final PrivateMarkerTransactionFactory privateMarkerTransactionFactory) {
this( this(
new Enclave(privacyParameters.getEnclaveUri()), new Enclave(privacyParameters.getEnclaveUri()),
Address.privacyPrecompiled(privacyParameters.getPrivacyAddress()),
privacyParameters.getSigningKeyPair(),
privacyParameters.getEnclavePublicKey(), privacyParameters.getEnclavePublicKey(),
privacyParameters.getPrivateStateStorage(), privacyParameters.getPrivateStateStorage(),
privacyParameters.getPrivateWorldStateArchive(), privacyParameters.getPrivateWorldStateArchive(),
new PrivateTransactionValidator(chainId)); new PrivateTransactionValidator(chainId),
privateMarkerTransactionFactory);
} }
public PrivateTransactionHandler( public PrivateTransactionHandler(
final Enclave enclave, final Enclave enclave,
final Address privacyPrecompileAddress,
final SECP256K1.KeyPair nodeKeyPair,
final String enclavePublicKey, final String enclavePublicKey,
final PrivateStateStorage privateStateStorage, final PrivateStateStorage privateStateStorage,
final WorldStateArchive privateWorldStateArchive, final WorldStateArchive privateWorldStateArchive,
final PrivateTransactionValidator privateTransactionValidator) { final PrivateTransactionValidator privateTransactionValidator,
final PrivateMarkerTransactionFactory privateMarkerTransactionFactory) {
this.enclave = enclave; this.enclave = enclave;
this.privacyPrecompileAddress = privacyPrecompileAddress;
this.nodeKeyPair = nodeKeyPair;
this.signerAddress = Util.publicKeyToAddress(nodeKeyPair.getPublicKey());
this.enclavePublicKey = enclavePublicKey; this.enclavePublicKey = enclavePublicKey;
this.privateStateStorage = privateStateStorage; this.privateStateStorage = privateStateStorage;
this.privateWorldStateArchive = privateWorldStateArchive; this.privateWorldStateArchive = privateWorldStateArchive;
this.privateTransactionValidator = privateTransactionValidator; this.privateTransactionValidator = privateTransactionValidator;
this.privateMarkerTransactionFactory = privateMarkerTransactionFactory;
} }
public String sendToOrion(final PrivateTransaction privateTransaction) throws Exception { public String sendToOrion(final PrivateTransaction privateTransaction) throws Exception {
@ -117,19 +112,8 @@ public class PrivateTransactionHandler {
} }
public Transaction createPrivacyMarkerTransaction( public Transaction createPrivacyMarkerTransaction(
final String transactionEnclaveKey, final String transactionEnclaveKey, final PrivateTransaction privateTransaction) {
final PrivateTransaction privateTransaction, return privateMarkerTransactionFactory.create(transactionEnclaveKey, privateTransaction);
final Long nonce) {
return Transaction.builder()
.nonce(nonce)
.gasPrice(privateTransaction.getGasPrice())
.gasLimit(privateTransaction.getGasLimit())
.to(privacyPrecompileAddress)
.value(privateTransaction.getValue())
.payload(BytesValues.fromBase64(transactionEnclaveKey))
.sender(signerAddress)
.signAndBuild(nodeKeyPair);
} }
public ValidationResult<TransactionInvalidReason> validatePrivateTransaction( public ValidationResult<TransactionInvalidReason> validatePrivateTransaction(
@ -187,12 +171,4 @@ public class PrivateTransactionHandler {
// private state does not exist // private state does not exist
Account.DEFAULT_NONCE); Account.DEFAULT_NONCE);
} }
public Address getSignerAddress() {
return signerAddress;
}
public String getEnclaveKey() {
return enclavePublicKey;
}
} }

@ -0,0 +1,45 @@
/*
* 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.markertransaction;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.Transaction;
import tech.pegasys.pantheon.ethereum.core.Util;
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransaction;
import tech.pegasys.pantheon.ethereum.util.NonceProvider;
public class FixedKeySigningPrivateMarkerTransactionFactory
extends PrivateMarkerTransactionFactory {
private final NonceProvider nonceProvider;
private final KeyPair signingKey;
private final Address sender;
public FixedKeySigningPrivateMarkerTransactionFactory(
final Address privacyPrecompileAddress,
final NonceProvider nonceProvider,
final KeyPair signingKey) {
super(privacyPrecompileAddress);
this.nonceProvider = nonceProvider;
this.signingKey = signingKey;
this.sender = Util.publicKeyToAddress(signingKey.getPublicKey());
}
@Override
public Transaction create(
final String transactionEnclaveKey, final PrivateTransaction privateTransaction) {
return create(
transactionEnclaveKey, privateTransaction, nonceProvider.getNonce(sender), signingKey);
}
}

@ -0,0 +1,50 @@
/*
* 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.markertransaction;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.Transaction;
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransaction;
import tech.pegasys.pantheon.util.bytes.BytesValues;
public abstract class PrivateMarkerTransactionFactory {
private final Address privacyPrecompileAddress;
public PrivateMarkerTransactionFactory(final Address privacyPrecompileAddress) {
this.privacyPrecompileAddress = privacyPrecompileAddress;
}
private Address getPrivacyPrecompileAddress() {
return privacyPrecompileAddress;
}
public abstract Transaction create(
final String transactionEnclaveKey, final PrivateTransaction privateTransaction);
protected Transaction create(
final String transactionEnclaveKey,
final PrivateTransaction privateTransaction,
final long nonce,
final KeyPair signingKey) {
return Transaction.builder()
.nonce(nonce)
.gasPrice(privateTransaction.getGasPrice())
.gasLimit(privateTransaction.getGasLimit())
.to(getPrivacyPrecompileAddress())
.value(privateTransaction.getValue())
.payload(BytesValues.fromBase64(transactionEnclaveKey))
.signAndBuild(signingKey);
}
}

@ -0,0 +1,32 @@
/*
* 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.markertransaction;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.Transaction;
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransaction;
public class RandomSigningPrivateMarkerTransactionFactory extends PrivateMarkerTransactionFactory {
public RandomSigningPrivateMarkerTransactionFactory(final Address privacyPrecompileAddress) {
super(privacyPrecompileAddress);
}
@Override
public Transaction create(
final String transactionEnclaveKey, final PrivateTransaction privateTransaction) {
final KeyPair signingKey = KeyPair.generate();
return create(transactionEnclaveKey, privateTransaction, 0, signingKey);
}
}

@ -0,0 +1,21 @@
/*
* 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.util;
import tech.pegasys.pantheon.ethereum.core.Address;
@FunctionalInterface
public interface NonceProvider {
long getNonce(final Address address);
}

@ -35,6 +35,7 @@ import tech.pegasys.pantheon.ethereum.core.Transaction;
import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.core.Wei;
import tech.pegasys.pantheon.ethereum.mainnet.TransactionValidator.TransactionInvalidReason; import tech.pegasys.pantheon.ethereum.mainnet.TransactionValidator.TransactionInvalidReason;
import tech.pegasys.pantheon.ethereum.mainnet.ValidationResult; import tech.pegasys.pantheon.ethereum.mainnet.ValidationResult;
import tech.pegasys.pantheon.ethereum.privacy.markertransaction.FixedKeySigningPrivateMarkerTransactionFactory;
import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive; import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive;
import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.bytes.BytesValue;
import tech.pegasys.pantheon.util.bytes.BytesValues; import tech.pegasys.pantheon.util.bytes.BytesValues;
@ -114,21 +115,21 @@ public class PrivateTransactionHandlerTest {
privateTransactionHandler = privateTransactionHandler =
new PrivateTransactionHandler( new PrivateTransactionHandler(
mockEnclave(), mockEnclave(),
Address.DEFAULT_PRIVACY,
KEY_PAIR,
OrionKeyUtils.loadKey("orion_key_0.pub"), OrionKeyUtils.loadKey("orion_key_0.pub"),
privateStateStorage, privateStateStorage,
worldStateArchive, worldStateArchive,
privateTransactionValidator); privateTransactionValidator,
new FixedKeySigningPrivateMarkerTransactionFactory(
Address.DEFAULT_PRIVACY, (address) -> 0, KEY_PAIR));
brokenPrivateTransactionHandler = brokenPrivateTransactionHandler =
new PrivateTransactionHandler( new PrivateTransactionHandler(
brokenMockEnclave(), brokenMockEnclave(),
Address.DEFAULT_PRIVACY,
KEY_PAIR,
OrionKeyUtils.loadKey("orion_key_0.pub"), OrionKeyUtils.loadKey("orion_key_0.pub"),
privateStateStorage, privateStateStorage,
worldStateArchive, worldStateArchive,
privateTransactionValidator); privateTransactionValidator,
new FixedKeySigningPrivateMarkerTransactionFactory(
Address.DEFAULT_PRIVACY, (address) -> 0, KEY_PAIR));
} }
@Test @Test
@ -145,7 +146,7 @@ public class PrivateTransactionHandlerTest {
privateTransactionHandler.validatePrivateTransaction(transaction, privacyGroupId); privateTransactionHandler.validatePrivateTransaction(transaction, privacyGroupId);
final Transaction markerTransaction = final Transaction markerTransaction =
privateTransactionHandler.createPrivacyMarkerTransaction(enclaveKey, transaction, 0L); privateTransactionHandler.createPrivacyMarkerTransaction(enclaveKey, transaction);
assertThat(validationResult).isEqualTo(ValidationResult.valid()); assertThat(validationResult).isEqualTo(ValidationResult.valid());
assertThat(markerTransaction.contractAddress()).isEqualTo(PUBLIC_TRANSACTION.contractAddress()); assertThat(markerTransaction.contractAddress()).isEqualTo(PUBLIC_TRANSACTION.contractAddress());
@ -167,7 +168,7 @@ public class PrivateTransactionHandlerTest {
transaction, transaction.getPrivacyGroupId().get().toString()); transaction, transaction.getPrivacyGroupId().get().toString());
final Transaction markerTransaction = final Transaction markerTransaction =
privateTransactionHandler.createPrivacyMarkerTransaction(enclaveKey, transaction, 0L); privateTransactionHandler.createPrivacyMarkerTransaction(enclaveKey, transaction);
assertThat(validationResult).isEqualTo(ValidationResult.valid()); assertThat(validationResult).isEqualTo(ValidationResult.valid());
assertThat(markerTransaction.contractAddress()).isEqualTo(PUBLIC_TRANSACTION.contractAddress()); assertThat(markerTransaction.contractAddress()).isEqualTo(PUBLIC_TRANSACTION.contractAddress());

@ -0,0 +1,75 @@
/*
* 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.markertransaction;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.Transaction;
import tech.pegasys.pantheon.ethereum.core.Util;
import tech.pegasys.pantheon.ethereum.core.Wei;
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransaction;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import java.util.Base64;
import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
public class FixedKeySigningPrivateMarkerTransactionFactoryTest {
private final PrivateTransaction privTransaction = mock(PrivateTransaction.class);
private final Wei gasPrice = Wei.of(100);
private final long gasLimit = 500;
private final Wei value = Wei.ZERO;
private final long providedNonce = 100;
private final String enclaveKey = "enclaveKey";
@Before
public void setup() {
when(privTransaction.getGasPrice()).thenReturn(gasPrice);
when(privTransaction.getGasLimit()).thenReturn(gasLimit);
when(privTransaction.getValue()).thenReturn(value);
}
@Test
public void createsFullyPopulatedPrivateMarkerTransactionUsingProvidedNonce() {
final KeyPair signingKeys = KeyPair.generate();
final Address precompiledAddress = Address.fromHexString("1");
final FixedKeySigningPrivateMarkerTransactionFactory factory =
new FixedKeySigningPrivateMarkerTransactionFactory(
precompiledAddress, (address) -> providedNonce, signingKeys);
final Transaction transaction = factory.create(enclaveKey, privTransaction);
assertThat(transaction.getNonce()).isEqualTo(providedNonce);
assertThat(transaction.getGasLimit()).isEqualTo(privTransaction.getGasLimit());
assertThat(transaction.getGasPrice()).isEqualTo(privTransaction.getGasPrice());
assertThat(transaction.getValue()).isEqualTo(privTransaction.getValue());
assertThat(transaction.getSender())
.isEqualTo(Util.publicKeyToAddress(signingKeys.getPublicKey()));
assertThat(transaction.getTo()).isEqualTo(Optional.of(precompiledAddress));
assertThat(transaction.getPayload())
.isEqualTo(BytesValue.wrap(Base64.getDecoder().decode(enclaveKey)));
final Transaction nextTransaction = factory.create("enclaveKey", privTransaction);
assertThat(nextTransaction.getSender()).isEqualTo(transaction.getSender());
}
}

@ -0,0 +1,67 @@
/*
* Copyright 2019 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package tech.pegasys.pantheon.ethereum.privacy.markertransaction;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
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.ethereum.privacy.PrivateTransaction;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import java.util.Base64;
import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
public class RandomSigningPrivateMarkerTransactionFactoryTest {
private final PrivateTransaction privTransaction = mock(PrivateTransaction.class);
private final Wei gasPrice = Wei.of(100);
private final long gasLimit = 500;
private final Wei value = Wei.ZERO;
private final String enclaveKey = "enclaveKey";
@Before
public void setup() {
when(privTransaction.getGasPrice()).thenReturn(gasPrice);
when(privTransaction.getGasLimit()).thenReturn(gasLimit);
when(privTransaction.getValue()).thenReturn(value);
}
@Test
public void producedTransactionHasZeroNonceAndDifferentSendThanPrior() {
final Address precompiledAddress = Address.fromHexString("1");
final RandomSigningPrivateMarkerTransactionFactory factory =
new RandomSigningPrivateMarkerTransactionFactory(precompiledAddress);
final Transaction transaction = factory.create(enclaveKey, privTransaction);
assertThat(transaction.getNonce()).isEqualTo(0);
assertThat(transaction.getGasLimit()).isEqualTo(privTransaction.getGasLimit());
assertThat(transaction.getGasPrice()).isEqualTo(privTransaction.getGasPrice());
assertThat(transaction.getValue()).isEqualTo(privTransaction.getValue());
assertThat(transaction.getTo()).isEqualTo(Optional.of(precompiledAddress));
assertThat(transaction.getPayload())
.isEqualTo(BytesValue.wrap(Base64.getDecoder().decode(enclaveKey)));
final Transaction nextTransaction = factory.create("enclaveKey", privTransaction);
assertThat(nextTransaction.getSender()).isNotEqualTo(transaction.getSender());
}
}

@ -16,8 +16,10 @@ import tech.pegasys.pantheon.config.GenesisConfigOptions;
import tech.pegasys.pantheon.enclave.Enclave; import tech.pegasys.pantheon.enclave.Enclave;
import tech.pegasys.pantheon.ethereum.blockcreation.MiningCoordinator; import tech.pegasys.pantheon.ethereum.blockcreation.MiningCoordinator;
import tech.pegasys.pantheon.ethereum.chain.Blockchain; import tech.pegasys.pantheon.ethereum.chain.Blockchain;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.PrivacyParameters; import tech.pegasys.pantheon.ethereum.core.PrivacyParameters;
import tech.pegasys.pantheon.ethereum.core.Synchronizer; import tech.pegasys.pantheon.ethereum.core.Synchronizer;
import tech.pegasys.pantheon.ethereum.eth.transactions.PendingTransactions;
import tech.pegasys.pantheon.ethereum.eth.transactions.TransactionPool; import tech.pegasys.pantheon.ethereum.eth.transactions.TransactionPool;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.filter.FilterManager; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.filter.FilterManager;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.AdminAddPeer; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.AdminAddPeer;
@ -114,6 +116,9 @@ import tech.pegasys.pantheon.ethereum.p2p.rlpx.wire.Capability;
import tech.pegasys.pantheon.ethereum.permissioning.AccountLocalConfigPermissioningController; import tech.pegasys.pantheon.ethereum.permissioning.AccountLocalConfigPermissioningController;
import tech.pegasys.pantheon.ethereum.permissioning.NodeLocalConfigPermissioningController; import tech.pegasys.pantheon.ethereum.permissioning.NodeLocalConfigPermissioningController;
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionHandler; import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionHandler;
import tech.pegasys.pantheon.ethereum.privacy.markertransaction.FixedKeySigningPrivateMarkerTransactionFactory;
import tech.pegasys.pantheon.ethereum.privacy.markertransaction.PrivateMarkerTransactionFactory;
import tech.pegasys.pantheon.ethereum.privacy.markertransaction.RandomSigningPrivateMarkerTransactionFactory;
import tech.pegasys.pantheon.ethereum.transaction.TransactionSimulator; import tech.pegasys.pantheon.ethereum.transaction.TransactionSimulator;
import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive; import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive;
import tech.pegasys.pantheon.metrics.MetricsSystem; import tech.pegasys.pantheon.metrics.MetricsSystem;
@ -328,15 +333,19 @@ public class JsonRpcMethodsFactory {
boolean eea = rpcApis.contains(RpcApis.EEA), priv = rpcApis.contains(RpcApis.PRIV); boolean eea = rpcApis.contains(RpcApis.EEA), priv = rpcApis.contains(RpcApis.PRIV);
if (eea || priv) { if (eea || priv) {
final PrivateMarkerTransactionFactory markerTransactionFactory =
createPrivateMarkerTransactionFactory(
privacyParameters, blockchainQueries, transactionPool.getPendingTransactions());
final PrivateTransactionHandler privateTransactionHandler = final PrivateTransactionHandler privateTransactionHandler =
new PrivateTransactionHandler(privacyParameters, protocolSchedule.getChainId()); new PrivateTransactionHandler(
privacyParameters, protocolSchedule.getChainId(), markerTransactionFactory);
final Enclave enclave = new Enclave(privacyParameters.getEnclaveUri()); final Enclave enclave = new Enclave(privacyParameters.getEnclaveUri());
if (eea) { if (eea) {
addMethods( addMethods(
enabledMethods, enabledMethods,
new EeaGetTransactionReceipt(blockchainQueries, enclave, parameter, privacyParameters), new EeaGetTransactionReceipt(blockchainQueries, enclave, parameter, privacyParameters),
new EeaSendRawTransaction( new EeaSendRawTransaction(privateTransactionHandler, transactionPool, parameter));
blockchainQueries, privateTransactionHandler, transactionPool, parameter));
} }
if (priv) { if (priv) {
addMethods( addMethods(
@ -362,4 +371,21 @@ public class JsonRpcMethodsFactory {
methods.put(rpcMethod.getName(), rpcMethod); methods.put(rpcMethod.getName(), rpcMethod);
} }
} }
private PrivateMarkerTransactionFactory createPrivateMarkerTransactionFactory(
final PrivacyParameters privacyParameters,
final BlockchainQueries blockchainQueries,
final PendingTransactions pendingTransactions) {
final Address privateContractAddress =
Address.privacyPrecompiled(privacyParameters.getPrivacyAddress());
if (privacyParameters.getSigningKeyPair().isPresent()) {
return new FixedKeySigningPrivateMarkerTransactionFactory(
privateContractAddress,
new LatestNonceProvider(blockchainQueries, pendingTransactions),
privacyParameters.getSigningKeyPair().get());
}
return new RandomSigningPrivateMarkerTransactionFactory(privateContractAddress);
}
} }

@ -0,0 +1,39 @@
/*
* Copyright 2019 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package tech.pegasys.pantheon.ethereum.jsonrpc;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.eth.transactions.PendingTransactions;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries;
import tech.pegasys.pantheon.ethereum.util.NonceProvider;
import java.util.OptionalLong;
public class LatestNonceProvider implements NonceProvider {
private final BlockchainQueries blockchainQueries;
private final PendingTransactions pendingTransactions;
public LatestNonceProvider(
final BlockchainQueries blockchainQueries, final PendingTransactions pendingTransactions) {
this.blockchainQueries = blockchainQueries;
this.pendingTransactions = pendingTransactions;
}
@Override
public long getNonce(final Address address) {
final OptionalLong pendingNonce = pendingTransactions.getNextNonceForSender(address);
return pendingNonce.orElseGet(
() -> blockchainQueries.getTransactionCount(address, blockchainQueries.headBlockNumber()));
}
}

@ -15,16 +15,13 @@ package tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.privacy.eea;
import static tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcEnclaveErrorConverter.convertEnclaveInvalidReason; import static tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcEnclaveErrorConverter.convertEnclaveInvalidReason;
import static tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcErrorConverter.convertTransactionInvalidReason; import static tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcErrorConverter.convertTransactionInvalidReason;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.Transaction; import tech.pegasys.pantheon.ethereum.core.Transaction;
import tech.pegasys.pantheon.ethereum.eth.transactions.PendingTransactions;
import tech.pegasys.pantheon.ethereum.eth.transactions.TransactionPool; import tech.pegasys.pantheon.ethereum.eth.transactions.TransactionPool;
import tech.pegasys.pantheon.ethereum.jsonrpc.RpcMethod; import tech.pegasys.pantheon.ethereum.jsonrpc.RpcMethod;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.exception.InvalidJsonRpcRequestException; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.exception.InvalidJsonRpcRequestException;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.JsonRpcMethod; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.JsonRpcMethod;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcError; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcError;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcErrorResponse; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcErrorResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse;
@ -36,8 +33,6 @@ import tech.pegasys.pantheon.ethereum.rlp.RLP;
import tech.pegasys.pantheon.ethereum.rlp.RLPException; import tech.pegasys.pantheon.ethereum.rlp.RLPException;
import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.bytes.BytesValue;
import java.util.OptionalLong;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@ -45,22 +40,17 @@ public class EeaSendRawTransaction implements JsonRpcMethod {
private static final Logger LOG = LogManager.getLogger(); private static final Logger LOG = LogManager.getLogger();
private final BlockchainQueries blockchain;
private final PrivateTransactionHandler privateTransactionHandler; private final PrivateTransactionHandler privateTransactionHandler;
private final TransactionPool transactionPool; private final TransactionPool transactionPool;
private final JsonRpcParameter parameters; private final JsonRpcParameter parameters;
private final PendingTransactions pendingTransactions;
public EeaSendRawTransaction( public EeaSendRawTransaction(
final BlockchainQueries blockchain,
final PrivateTransactionHandler privateTransactionHandler, final PrivateTransactionHandler privateTransactionHandler,
final TransactionPool transactionPool, final TransactionPool transactionPool,
final JsonRpcParameter parameters) { final JsonRpcParameter parameters) {
this.blockchain = blockchain;
this.privateTransactionHandler = privateTransactionHandler; this.privateTransactionHandler = privateTransactionHandler;
this.transactionPool = transactionPool; this.transactionPool = transactionPool;
this.parameters = parameters; this.parameters = parameters;
this.pendingTransactions = transactionPool.getPendingTransactions();
} }
@Override @Override
@ -112,9 +102,7 @@ public class EeaSendRawTransaction implements JsonRpcMethod {
() -> { () -> {
final Transaction privacyMarkerTransaction = final Transaction privacyMarkerTransaction =
privateTransactionHandler.createPrivacyMarkerTransaction( privateTransactionHandler.createPrivacyMarkerTransaction(
enclaveKey, enclaveKey, privateTransaction);
privateTransaction,
getNonce(privateTransactionHandler.getSignerAddress()));
return transactionPool return transactionPool
.addLocalTransaction(privacyMarkerTransaction) .addLocalTransaction(privacyMarkerTransaction)
.either( .either(
@ -139,10 +127,4 @@ public class EeaSendRawTransaction implements JsonRpcMethod {
throw new InvalidJsonRpcRequestException("Invalid raw private transaction hex", e); throw new InvalidJsonRpcRequestException("Invalid raw private transaction hex", e);
} }
} }
protected long getNonce(final Address address) {
final OptionalLong pendingNonce = pendingTransactions.getNextNonceForSender(address);
return pendingNonce.orElseGet(
() -> blockchain.getTransactionCount(address, blockchain.headBlockNumber()));
}
} }

@ -0,0 +1,54 @@
/*
* Copyright 2019 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package tech.pegasys.pantheon.ethereum.jsonrpc;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.eth.transactions.PendingTransactions;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries;
import java.util.OptionalLong;
import org.junit.Test;
public class LatestNonceProviderTest {
private final Address senderAdress = Address.fromHexString("1");
private PendingTransactions pendingTransactions = mock(PendingTransactions.class);
private BlockchainQueries blockchainQueries = mock(BlockchainQueries.class);
private LatestNonceProvider nonceProvider =
new LatestNonceProvider(blockchainQueries, pendingTransactions);
@Test
public void nextNonceUsesTxPool() {
final long highestNonceInPendingTransactions = 123;
when(pendingTransactions.getNextNonceForSender(senderAdress))
.thenReturn(OptionalLong.of(highestNonceInPendingTransactions));
assertThat(nonceProvider.getNonce(senderAdress)).isEqualTo(highestNonceInPendingTransactions);
}
@Test
public void nextNonceIsTakenFromBlockchainIfNoPendingTransactionResponse() {
final long headBlockNumber = 8;
final long nonceInBLockchain = 56;
when(pendingTransactions.getNextNonceForSender(senderAdress)).thenReturn(OptionalLong.empty());
when(blockchainQueries.headBlockNumber()).thenReturn(headBlockNumber);
when(blockchainQueries.getTransactionCount(senderAdress, headBlockNumber))
.thenReturn(nonceInBLockchain);
assertThat(nonceProvider.getNonce(senderAdress)).isEqualTo(nonceInBLockchain);
}
}

@ -23,11 +23,9 @@ import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.Transaction; import tech.pegasys.pantheon.ethereum.core.Transaction;
import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.core.Wei;
import tech.pegasys.pantheon.ethereum.eth.transactions.PendingTransactions;
import tech.pegasys.pantheon.ethereum.eth.transactions.TransactionPool; import tech.pegasys.pantheon.ethereum.eth.transactions.TransactionPool;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcError; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcError;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcErrorResponse; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcErrorResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse;
@ -41,7 +39,6 @@ import tech.pegasys.pantheon.util.bytes.BytesValue;
import java.io.IOException; import java.io.IOException;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.Optional; import java.util.Optional;
import java.util.OptionalLong;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -118,15 +115,9 @@ public class EeaSendRawTransactionTest {
@Mock private PrivateTransactionHandler privateTxHandler; @Mock private PrivateTransactionHandler privateTxHandler;
@Mock private BlockchainQueries blockchainQueries;
@Mock private PendingTransactions pendingTransactions;
@Before @Before
public void before() { public void before() {
when(transactionPool.getPendingTransactions()).thenReturn(pendingTransactions); method = new EeaSendRawTransaction(privateTxHandler, transactionPool, parameter);
method =
new EeaSendRawTransaction(blockchainQueries, privateTxHandler, transactionPool, parameter);
} }
@Test @Test
@ -211,7 +202,7 @@ public class EeaSendRawTransactionTest {
any(PrivateTransaction.class), any(String.class))) any(PrivateTransaction.class), any(String.class)))
.thenReturn(ValidationResult.valid()); .thenReturn(ValidationResult.valid());
when(privateTxHandler.createPrivacyMarkerTransaction( when(privateTxHandler.createPrivacyMarkerTransaction(
any(String.class), any(PrivateTransaction.class), any(Long.class))) any(String.class), any(PrivateTransaction.class)))
.thenReturn(PUBLIC_TRANSACTION); .thenReturn(PUBLIC_TRANSACTION);
when(transactionPool.addLocalTransaction(any(Transaction.class))) when(transactionPool.addLocalTransaction(any(Transaction.class)))
.thenReturn(ValidationResult.valid()); .thenReturn(ValidationResult.valid());
@ -231,8 +222,7 @@ public class EeaSendRawTransactionTest {
verify(privateTxHandler) verify(privateTxHandler)
.validatePrivateTransaction(any(PrivateTransaction.class), any(String.class)); .validatePrivateTransaction(any(PrivateTransaction.class), any(String.class));
verify(privateTxHandler) verify(privateTxHandler)
.createPrivacyMarkerTransaction( .createPrivacyMarkerTransaction(any(String.class), any(PrivateTransaction.class));
any(String.class), any(PrivateTransaction.class), any(Long.class));
verify(transactionPool).addLocalTransaction(any(Transaction.class)); verify(transactionPool).addLocalTransaction(any(Transaction.class));
} }
@ -247,7 +237,7 @@ public class EeaSendRawTransactionTest {
any(PrivateTransaction.class), any(String.class))) any(PrivateTransaction.class), any(String.class)))
.thenReturn(ValidationResult.valid()); .thenReturn(ValidationResult.valid());
when(privateTxHandler.createPrivacyMarkerTransaction( when(privateTxHandler.createPrivacyMarkerTransaction(
any(String.class), any(PrivateTransaction.class), any(Long.class))) any(String.class), any(PrivateTransaction.class)))
.thenReturn(PUBLIC_TRANSACTION); .thenReturn(PUBLIC_TRANSACTION);
when(transactionPool.addLocalTransaction(any(Transaction.class))) when(transactionPool.addLocalTransaction(any(Transaction.class)))
.thenReturn(ValidationResult.valid()); .thenReturn(ValidationResult.valid());
@ -270,8 +260,7 @@ public class EeaSendRawTransactionTest {
verify(privateTxHandler) verify(privateTxHandler)
.validatePrivateTransaction(any(PrivateTransaction.class), any(String.class)); .validatePrivateTransaction(any(PrivateTransaction.class), any(String.class));
verify(privateTxHandler) verify(privateTxHandler)
.createPrivacyMarkerTransaction( .createPrivacyMarkerTransaction(any(String.class), any(PrivateTransaction.class));
any(String.class), any(PrivateTransaction.class), any(Long.class));
verify(transactionPool).addLocalTransaction(any(Transaction.class)); verify(transactionPool).addLocalTransaction(any(Transaction.class));
} }
@ -370,7 +359,7 @@ public class EeaSendRawTransactionTest {
any(PrivateTransaction.class), any(String.class))) any(PrivateTransaction.class), any(String.class)))
.thenReturn(ValidationResult.valid()); .thenReturn(ValidationResult.valid());
when(privateTxHandler.createPrivacyMarkerTransaction( when(privateTxHandler.createPrivacyMarkerTransaction(
any(String.class), any(PrivateTransaction.class), any(Long.class))) any(String.class), any(PrivateTransaction.class)))
.thenReturn(PUBLIC_TRANSACTION); .thenReturn(PUBLIC_TRANSACTION);
when(transactionPool.addLocalTransaction(any(Transaction.class))) when(transactionPool.addLocalTransaction(any(Transaction.class)))
.thenReturn(ValidationResult.invalid(transactionInvalidReason)); .thenReturn(ValidationResult.invalid(transactionInvalidReason));
@ -389,18 +378,10 @@ public class EeaSendRawTransactionTest {
verify(privateTxHandler) verify(privateTxHandler)
.validatePrivateTransaction(any(PrivateTransaction.class), any(String.class)); .validatePrivateTransaction(any(PrivateTransaction.class), any(String.class));
verify(privateTxHandler) verify(privateTxHandler)
.createPrivacyMarkerTransaction( .createPrivacyMarkerTransaction(any(String.class), any(PrivateTransaction.class));
any(String.class), any(PrivateTransaction.class), any(Long.class));
verify(transactionPool).addLocalTransaction(any(Transaction.class)); verify(transactionPool).addLocalTransaction(any(Transaction.class));
} }
@Test
public void nextNonceUsesTxPool() {
Address address = PUBLIC_TRANSACTION.getSender();
when(pendingTransactions.getNextNonceForSender(address)).thenReturn(OptionalLong.of(123));
assertThat(method.getNonce(address)).isEqualTo(123);
}
@Test @Test
public void getMethodReturnsExpectedName() { public void getMethodReturnsExpectedName() {
assertThat(method.getName()).matches("eea_sendRawTransaction"); assertThat(method.getName()).matches("eea_sendRawTransaction");

@ -602,6 +602,12 @@ public class PantheonCommand implements DefaultCommandValues, Runnable {
"The address to which the privacy pre-compiled contract will be mapped to (default: ${DEFAULT-VALUE})") "The address to which the privacy pre-compiled contract will be mapped to (default: ${DEFAULT-VALUE})")
private final Integer privacyPrecompiledAddress = Address.PRIVACY; private final Integer privacyPrecompiledAddress = Address.PRIVACY;
@Option(
names = {"--privacy-marker-transaction-signing-key-file"},
description =
"The name of a file containing the private key used to sign privacy marker transactions. If unset, each will be signed with a random key.")
private final Path privacyMarkerTransactionSigningKeyPath = null;
@Option( @Option(
names = {"--tx-pool-max-size"}, names = {"--tx-pool-max-size"},
paramLabel = MANDATORY_INTEGER_FORMAT_HELP, paramLabel = MANDATORY_INTEGER_FORMAT_HELP,
@ -1150,6 +1156,7 @@ public class PantheonCommand implements DefaultCommandValues, Runnable {
privacyParametersBuilder.setPrivacyAddress(privacyPrecompiledAddress); privacyParametersBuilder.setPrivacyAddress(privacyPrecompiledAddress);
privacyParametersBuilder.setMetricsSystem(metricsSystem.get()); privacyParametersBuilder.setMetricsSystem(metricsSystem.get());
privacyParametersBuilder.setDataDir(dataDir()); privacyParametersBuilder.setDataDir(dataDir());
privacyParametersBuilder.setPrivateKeyPath(privacyMarkerTransactionSigningKeyPath);
} }
return privacyParametersBuilder.build(); return privacyParametersBuilder.build();
} }

@ -182,7 +182,6 @@ public abstract class PantheonControllerBuilder<C> {
checkArgument( checkArgument(
storageProvider == null || rocksDbConfiguration == null, storageProvider == null || rocksDbConfiguration == null,
"Must supply either storage provider or RocksDB confguration, but not both"); "Must supply either storage provider or RocksDB confguration, but not both");
privacyParameters.setSigningKeyPair(nodeKeys);
if (storageProvider == null && rocksDbConfiguration != null) { if (storageProvider == null && rocksDbConfiguration != null) {
storageProvider = RocksDbStorageProvider.create(rocksDbConfiguration, metricsSystem); storageProvider = RocksDbStorageProvider.create(rocksDbConfiguration, metricsSystem);

@ -95,6 +95,7 @@ privacy-url="http://127.0.0.1:8888"
privacy-public-key-file="./pubKey.pub" privacy-public-key-file="./pubKey.pub"
privacy-enabled=false privacy-enabled=false
privacy-precompiled-address=9 privacy-precompiled-address=9
privacy-marker-transaction-signing-key-file="./signerKey"
# Transaction Pool # Transaction Pool
tx-pool-retention-hours=999 tx-pool-retention-hours=999

Loading…
Cancel
Save