From 500152850056786c21dc1c6a7108442bde425ed9 Mon Sep 17 00:00:00 2001 From: Ivaylo Kirilov Date: Mon, 8 Jul 2019 17:45:28 +0100 Subject: [PATCH] [PAN-2825] eea send raw transaction with privacy group id (#1611) * Add privacy group id to private transaction * Update enclave send methods to accept privacy group id * Update eea sendRawTransaction endpoint * extract privacy group id from private transaction if present * extract privateFor/privateFrom if privacy group id is not present * Fix tests * Change abstract class invocation to concrete class. * Utility method to load enclave public key --- .../acceptance/dsl/privacy/PrivacyNode.java | 3 +- .../pegasys/pantheon/enclave/EnclaveTest.java | 25 ++++- .../pantheon/enclave/types/SendRequest.java | 19 +--- .../enclave/types/SendRequestLegacy.java | 35 ++++++ .../enclave/types/SendRequestPantheon.java | 34 ++++++ ...acyPrecompiledContractIntegrationTest.java | 8 +- .../ethereum/privacy/PrivateTransaction.java | 103 +++++++++++++----- .../privacy/PrivateTransactionHandler.java | 54 ++++++--- .../PrivateTransactionHandlerTest.java | 75 +++++++++---- .../privacy/PrivateTransactionTest.java | 98 +++++++++++++++-- .../privacy/EeaSendRawTransaction.java | 5 +- .../privacy/EeaSendRawTransactionTest.java | 55 +++++++++- ...onKeyGenerator.java => OrionKeyUtils.java} | 23 +++- 13 files changed, 434 insertions(+), 103 deletions(-) create mode 100644 enclave/src/main/java/tech/pegasys/pantheon/enclave/types/SendRequestLegacy.java create mode 100644 enclave/src/main/java/tech/pegasys/pantheon/enclave/types/SendRequestPantheon.java rename testutil/src/main/java/tech/pegasys/orion/testutil/{OrionKeyGenerator.java => OrionKeyUtils.java} (66%) diff --git a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/privacy/PrivacyNode.java b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/privacy/PrivacyNode.java index 7cd47d1fce..e9091a4e6f 100644 --- a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/privacy/PrivacyNode.java +++ b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/privacy/PrivacyNode.java @@ -18,6 +18,7 @@ import tech.pegasys.orion.testutil.OrionTestHarness; import tech.pegasys.pantheon.enclave.Enclave; import tech.pegasys.pantheon.enclave.types.SendRequest; +import tech.pegasys.pantheon.enclave.types.SendRequestLegacy; import tech.pegasys.pantheon.ethereum.core.MiningParameters; import tech.pegasys.pantheon.ethereum.core.PrivacyParameters; import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration; @@ -100,7 +101,7 @@ public void testOrionConnection(final PrivacyNode... otherNodes) { Arrays.stream(otherNodes).map(node -> node.orion.nodeUrl()).toArray()))); Enclave orionEnclave = new Enclave(orion.clientUrl()); SendRequest sendRequest1 = - new SendRequest( + new SendRequestLegacy( "SGVsbG8sIFdvcmxkIQ==", orion.getPublicKeys().get(0), Arrays.stream(otherNodes) diff --git a/enclave/src/integration-test/java/tech/pegasys/pantheon/enclave/EnclaveTest.java b/enclave/src/integration-test/java/tech/pegasys/pantheon/enclave/EnclaveTest.java index b9abd938ac..0a9c91f284 100644 --- a/enclave/src/integration-test/java/tech/pegasys/pantheon/enclave/EnclaveTest.java +++ b/enclave/src/integration-test/java/tech/pegasys/pantheon/enclave/EnclaveTest.java @@ -25,6 +25,8 @@ import tech.pegasys.pantheon.enclave.types.ReceiveRequest; import tech.pegasys.pantheon.enclave.types.ReceiveResponse; import tech.pegasys.pantheon.enclave.types.SendRequest; +import tech.pegasys.pantheon.enclave.types.SendRequestLegacy; +import tech.pegasys.pantheon.enclave.types.SendRequestPantheon; import tech.pegasys.pantheon.enclave.types.SendResponse; import java.io.IOException; @@ -73,7 +75,28 @@ public void testSendAndReceive() throws Exception { List publicKeys = testHarness.getPublicKeys(); SendRequest sc = - new SendRequest(PAYLOAD, publicKeys.get(0), Lists.newArrayList(publicKeys.get(0))); + new SendRequestLegacy(PAYLOAD, publicKeys.get(0), Lists.newArrayList(publicKeys.get(0))); + SendResponse sr = enclave.send(sc); + + ReceiveRequest rc = new ReceiveRequest(sr.getKey(), publicKeys.get(0)); + ReceiveResponse rr = enclave.receive(rc); + + assertEquals(PAYLOAD, new String(rr.getPayload(), UTF_8)); + assertNotNull(rr.getPrivacyGroupId()); + } + + @Test + public void testSendWithPrivacyGroupAndReceive() throws Exception { + List publicKeys = testHarness.getPublicKeys(); + + CreatePrivacyGroupRequest privacyGroupRequest = + new CreatePrivacyGroupRequest(publicKeys.toArray(new String[0]), publicKeys.get(0), "", ""); + + PrivacyGroup privacyGroupResponse = enclave.createPrivacyGroup(privacyGroupRequest); + + SendRequest sc = + new SendRequestPantheon( + PAYLOAD, publicKeys.get(0), privacyGroupResponse.getPrivacyGroupId()); SendResponse sr = enclave.send(sc); ReceiveRequest rc = new ReceiveRequest(sr.getKey(), publicKeys.get(0)); diff --git a/enclave/src/main/java/tech/pegasys/pantheon/enclave/types/SendRequest.java b/enclave/src/main/java/tech/pegasys/pantheon/enclave/types/SendRequest.java index e50930bc51..5c2a29525f 100644 --- a/enclave/src/main/java/tech/pegasys/pantheon/enclave/types/SendRequest.java +++ b/enclave/src/main/java/tech/pegasys/pantheon/enclave/types/SendRequest.java @@ -14,24 +14,13 @@ import static java.nio.charset.StandardCharsets.UTF_8; -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -@JsonPropertyOrder({"payload", "from", "to"}) -public class SendRequest { +public abstract class SendRequest { private byte[] payload; private String from; - private List to; - public SendRequest( - @JsonProperty(value = "payload") final String payload, - @JsonProperty(value = "from") final String from, - @JsonProperty(value = "to") final List to) { + public SendRequest(final String payload, final String from) { this.payload = payload.getBytes(UTF_8); this.from = from; - this.to = to; } public byte[] getPayload() { @@ -41,8 +30,4 @@ public byte[] getPayload() { public String getFrom() { return from; } - - public List getTo() { - return to; - } } diff --git a/enclave/src/main/java/tech/pegasys/pantheon/enclave/types/SendRequestLegacy.java b/enclave/src/main/java/tech/pegasys/pantheon/enclave/types/SendRequestLegacy.java new file mode 100644 index 0000000000..d220589ed9 --- /dev/null +++ b/enclave/src/main/java/tech/pegasys/pantheon/enclave/types/SendRequestLegacy.java @@ -0,0 +1,35 @@ +/* + * Copyright 2019 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package tech.pegasys.pantheon.enclave.types; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonPropertyOrder({"payload", "from", "to"}) +public class SendRequestLegacy extends SendRequest { + private List to; + + public SendRequestLegacy( + @JsonProperty(value = "payload") final String payload, + @JsonProperty(value = "from") final String from, + @JsonProperty(value = "to") final List to) { + super(payload, from); + this.to = to; + } + + public List getTo() { + return to; + } +} diff --git a/enclave/src/main/java/tech/pegasys/pantheon/enclave/types/SendRequestPantheon.java b/enclave/src/main/java/tech/pegasys/pantheon/enclave/types/SendRequestPantheon.java new file mode 100644 index 0000000000..67f9229ad9 --- /dev/null +++ b/enclave/src/main/java/tech/pegasys/pantheon/enclave/types/SendRequestPantheon.java @@ -0,0 +1,34 @@ +/* + * Copyright 2019 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package tech.pegasys.pantheon.enclave.types; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonPropertyOrder({"payload", "from", "privacyGroupId"}) +public class SendRequestPantheon extends SendRequest { + private String privacyGroupId; + + public SendRequestPantheon( + @JsonProperty(value = "payload") final String payload, + @JsonProperty(value = "from") final String from, + @JsonProperty(value = "to") final String privacyGroupId) { + super(payload, from); + + this.privacyGroupId = privacyGroupId; + } + + public String getPrivacyGroupId() { + return privacyGroupId; + } +} diff --git a/ethereum/core/src/integration-test/java/tech/pegasys/pantheon/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractIntegrationTest.java b/ethereum/core/src/integration-test/java/tech/pegasys/pantheon/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractIntegrationTest.java index 8f4a03f403..59a44445d5 100644 --- a/ethereum/core/src/integration-test/java/tech/pegasys/pantheon/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractIntegrationTest.java +++ b/ethereum/core/src/integration-test/java/tech/pegasys/pantheon/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractIntegrationTest.java @@ -25,6 +25,7 @@ import tech.pegasys.orion.testutil.OrionTestHarnessFactory; import tech.pegasys.pantheon.enclave.Enclave; import tech.pegasys.pantheon.enclave.types.SendRequest; +import tech.pegasys.pantheon.enclave.types.SendRequestLegacy; import tech.pegasys.pantheon.enclave.types.SendResponse; import tech.pegasys.pantheon.ethereum.chain.Blockchain; import tech.pegasys.pantheon.ethereum.core.Address; @@ -151,7 +152,8 @@ public void testSendAndReceive() throws Exception { List publicKeys = testHarness.getPublicKeys(); String s = new String(VALID_PRIVATE_TRANSACTION_RLP_BASE64, UTF_8); - SendRequest sc = new SendRequest(s, publicKeys.get(0), Lists.newArrayList(publicKeys.get(0))); + SendRequest sc = + new SendRequestLegacy(s, publicKeys.get(0), Lists.newArrayList(publicKeys.get(0))); SendResponse sr = enclave.send(sc); PrivacyPrecompiledContract privacyPrecompiledContract = @@ -178,7 +180,7 @@ public void testNoPrivateKeyError() throws RuntimeException { publicKeys.add("noPrivateKey"); String s = new String(VALID_PRIVATE_TRANSACTION_RLP_BASE64, UTF_8); - SendRequest sc = new SendRequest(s, publicKeys.get(0), publicKeys); + SendRequest sc = new SendRequestLegacy(s, publicKeys.get(0), publicKeys); final Throwable thrown = catchThrowable(() -> enclave.send(sc)); @@ -191,7 +193,7 @@ public void testWrongPrivateKeyError() throws RuntimeException { publicKeys.add("noPrivateKenoPrivateKenoPrivateKenoPrivateK"); String s = new String(VALID_PRIVATE_TRANSACTION_RLP_BASE64, UTF_8); - SendRequest sc = new SendRequest(s, publicKeys.get(0), publicKeys); + SendRequest sc = new SendRequestLegacy(s, publicKeys.get(0), publicKeys); final Throwable thrown = catchThrowable(() -> enclave.send(sc)); diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransaction.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransaction.java index 691dccdf1e..79c0a915c9 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransaction.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransaction.java @@ -66,9 +66,11 @@ public class PrivateTransaction { private final Optional chainId; - private final BytesValue privateFrom; + private final Optional privacyGroupId; - private final List privateFor; + private final Optional privateFrom; + + private final Optional> privateFor; private final Restriction restriction; @@ -115,19 +117,32 @@ public static PrivateTransaction readFrom(final RLPInput input) throws RLPExcept final BigInteger r = BytesValues.asUnsignedBigInteger(input.readUInt256Scalar().getBytes()); final BigInteger s = BytesValues.asUnsignedBigInteger(input.readUInt256Scalar().getBytes()); final SECP256K1.Signature signature = SECP256K1.Signature.create(r, s, recId); - final BytesValue privateFrom = input.readBytesValue(); - final List privateFor = input.readList(RLPInput::readBytesValue); + final BytesValue tempValue = input.readBytesValue(); + Optional> privateFor = Optional.empty(); + if (input.nextIsList()) { + privateFor = Optional.of(input.readList(RLPInput::readBytesValue)); + } + final Restriction restriction = convertToEnum(input.readBytesValue()); input.leaveList(); chainId.ifPresent(builder::chainId); - return builder - .signature(signature) - .privateFrom(privateFrom) - .privateFor(privateFor) - .restriction(restriction) - .build(); + + if (privateFor.isPresent()) { + return builder + .signature(signature) + .privateFrom(tempValue) + .privateFor(privateFor.get()) + .restriction(restriction) + .build(); + } else { + return builder + .signature(signature) + .privacyGroupId(tempValue) + .restriction(restriction) + .build(); + } } private static Restriction convertToEnum(final BytesValue readBytesValue) { @@ -155,6 +170,7 @@ private static Restriction convertToEnum(final BytesValue readBytesValue) { * otherwise it should contain an address. *

The {@code chainId} must be greater than 0 to be applied to a specific chain; otherwise * it will default to any chain. + * @param privacyGroupId The privacy group id of this private transaction * @param privateFrom The public key of the sender of this private transaction * @param privateFor An array of the public keys of the intended recipients of this private * transaction @@ -170,8 +186,9 @@ protected PrivateTransaction( final BytesValue payload, final Address sender, final Optional chainId, - final BytesValue privateFrom, - final List privateFor, + final Optional privacyGroupId, + final Optional privateFrom, + final Optional> privateFor, final Restriction restriction) { this.nonce = nonce; this.gasPrice = gasPrice; @@ -182,6 +199,7 @@ protected PrivateTransaction( this.payload = payload; this.sender = sender; this.chainId = chainId; + this.privacyGroupId = privacyGroupId; this.privateFrom = privateFrom; this.privateFor = privateFor; this.restriction = restriction; @@ -265,12 +283,21 @@ public Optional getChainId() { return chainId; } + /** + * Returns the enclave privacy group id. + * + * @return the enclave privacy group id. + */ + public Optional getPrivacyGroupId() { + return privacyGroupId; + } + /** * Returns the enclave public key of the sender. * * @return the enclave public key of the sender. */ - public BytesValue getPrivateFrom() { + public Optional getPrivateFrom() { return privateFrom; } @@ -279,7 +306,7 @@ public BytesValue getPrivateFrom() { * * @return the enclave public keys of the receivers */ - public List getPrivateFor() { + public Optional> getPrivateFor() { return privateFor; } @@ -321,6 +348,7 @@ private Bytes32 getOrComputeSenderRecoveryHash() { value, payload, chainId, + privacyGroupId, privateFrom, privateFor, restriction.getBytes()); @@ -343,8 +371,10 @@ public void writeTo(final RLPOutput out) { out.writeUInt256Scalar(getValue()); out.writeBytesValue(getPayload()); writeSignature(out); - out.writeBytesValue(getPrivateFrom()); - out.writeList(getPrivateFor(), (bv, rlpO) -> rlpO.writeBytesValue(bv)); + getPrivacyGroupId().ifPresent(out::writeBytesValue); + getPrivateFrom().ifPresent(out::writeBytesValue); + getPrivateFor() + .ifPresent(privateFor -> out.writeList(privateFor, (bv, rlpO) -> rlpO.writeBytesValue(bv))); out.writeBytesValue(getRestriction().getBytes()); out.endList(); @@ -427,8 +457,9 @@ private static Bytes32 computeSenderRecoveryHash( final Wei value, final BytesValue payload, final Optional chainId, - final BytesValue privateFrom, - final List privateFor, + final Optional privacyGroupId, + final Optional privateFrom, + final Optional> privateFor, final BytesValue restriction) { return keccak256( RLP.encode( @@ -445,8 +476,9 @@ private static Bytes32 computeSenderRecoveryHash( out.writeUInt256Scalar(UInt256.ZERO); out.writeUInt256Scalar(UInt256.ZERO); } - out.writeBytesValue(privateFrom); - out.writeList(privateFor, (bv, rlpO) -> rlpO.writeBytesValue(bv)); + privacyGroupId.ifPresent(out::writeBytesValue); + privateFrom.ifPresent(out::writeBytesValue); + privateFor.ifPresent(pF -> out.writeList(pF, (bv, rlpO) -> rlpO.writeBytesValue(bv))); out.writeBytesValue(restriction); out.endList(); })); @@ -499,8 +531,14 @@ public String toString() { sb.append("sig=").append(getSignature()).append(", "); if (chainId.isPresent()) sb.append("chainId=").append(getChainId().get()).append(", "); sb.append("payload=").append(getPayload()); - sb.append("privateFrom=").append(getPrivateFrom()); - sb.append("privateFor=").append(Arrays.toString(getPrivateFor().toArray())); + if (getPrivacyGroupId().isPresent()) + sb.append("privacyGroupId=").append(getPrivacyGroupId().get()).append(", "); + if (getPrivateFrom().isPresent()) + sb.append("privateFrom=").append(getPrivateFrom().get()).append(", "); + if (getPrivateFor().isPresent()) + sb.append("privateFor=") + .append(Arrays.toString(getPrivateFor().get().toArray())) + .append(", "); sb.append("restriction=").append(getRestriction()); return sb.append("}").toString(); } @@ -532,9 +570,11 @@ public static class Builder { protected Optional chainId = Optional.empty(); - protected BytesValue privateFrom; + protected Optional privacyGroupId = Optional.empty(); + + protected Optional privateFrom = Optional.empty(); - protected List privateFor; + protected Optional> privateFor = Optional.empty(); protected Restriction restriction; @@ -583,13 +623,18 @@ public Builder signature(final SECP256K1.Signature signature) { return this; } + public Builder privacyGroupId(final BytesValue privacyGroupId) { + this.privacyGroupId = Optional.of(privacyGroupId); + return this; + } + public Builder privateFrom(final BytesValue privateFrom) { - this.privateFrom = privateFrom; + this.privateFrom = Optional.of(privateFrom); return this; } public Builder privateFor(final List privateFor) { - this.privateFor = privateFor; + this.privateFor = Optional.of(privateFor); return this; } @@ -599,6 +644,10 @@ public Builder restriction(final Restriction restriction) { } public PrivateTransaction build() { + if (privacyGroupId.isPresent() && (privateFrom.isPresent() || privateFor.isPresent())) { + throw new IllegalArgumentException( + "Private transaction should contain either privacyGroup by itself or privateFrom and privateFor together, but not both"); + } return new PrivateTransaction( nonce, gasPrice, @@ -609,6 +658,7 @@ public PrivateTransaction build() { payload, sender, chainId, + privacyGroupId, privateFrom, privateFor, restriction); @@ -632,6 +682,7 @@ protected SECP256K1.Signature computeSignature(final SECP256K1.KeyPair keys) { value, payload, chainId, + privacyGroupId, privateFrom, privateFor, restriction.getBytes()); 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 index 8a3c61424f..2a97c157c9 100644 --- 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 @@ -20,6 +20,8 @@ import tech.pegasys.pantheon.enclave.types.ReceiveRequest; import tech.pegasys.pantheon.enclave.types.ReceiveResponse; import tech.pegasys.pantheon.enclave.types.SendRequest; +import tech.pegasys.pantheon.enclave.types.SendRequestLegacy; +import tech.pegasys.pantheon.enclave.types.SendRequestPantheon; import tech.pegasys.pantheon.enclave.types.SendResponse; import tech.pegasys.pantheon.ethereum.core.Account; import tech.pegasys.pantheon.ethereum.core.Address; @@ -49,6 +51,7 @@ public class PrivateTransactionHandler { private final Address privacyPrecompileAddress; private final SECP256K1.KeyPair nodeKeyPair; private final Address signerAddress; + private final String enclavePublicKey; private final PrivateStateStorage privateStateStorage; private final WorldStateArchive privateWorldStateArchive; @@ -57,6 +60,7 @@ public PrivateTransactionHandler(final PrivacyParameters privacyParameters) { new Enclave(privacyParameters.getEnclaveUri()), Address.privacyPrecompiled(privacyParameters.getPrivacyAddress()), privacyParameters.getSigningKeyPair(), + privacyParameters.getEnclavePublicKey(), privacyParameters.getPrivateStateStorage(), privacyParameters.getPrivateWorldStateArchive()); } @@ -65,12 +69,14 @@ public PrivateTransactionHandler( final Enclave enclave, final Address privacyPrecompileAddress, final SECP256K1.KeyPair nodeKeyPair, + final String enclavePublicKey, final PrivateStateStorage privateStateStorage, final WorldStateArchive privateWorldStateArchive) { this.enclave = enclave; this.privacyPrecompileAddress = privacyPrecompileAddress; this.nodeKeyPair = nodeKeyPair; this.signerAddress = Util.publicKeyToAddress(nodeKeyPair.getPublicKey()); + this.enclavePublicKey = enclavePublicKey; this.privateStateStorage = privateStateStorage; this.privateWorldStateArchive = privateWorldStateArchive; } @@ -89,9 +95,16 @@ public String sendToOrion(final PrivateTransaction privateTransaction) throws Ex } } - public String getPrivacyGroup(final String key, final BytesValue from) throws Exception { - final ReceiveRequest receiveRequest = new ReceiveRequest(key, BytesValues.asString(from)); - LOG.debug("Getting privacy group for {}", BytesValues.asString(from)); + public String getPrivacyGroup(final String key, final PrivateTransaction privateTransaction) + throws Exception { + if (privateTransaction.getPrivacyGroupId().isPresent()) { + return privateTransaction.getPrivacyGroupId().get().toString(); + } + final ReceiveRequest receiveRequest = + new ReceiveRequest(key, BytesValues.asString(privateTransaction.getPrivateFrom().get())); + LOG.debug( + "Getting privacy group for {}", + BytesValues.asString(privateTransaction.getPrivateFrom().get())); final ReceiveResponse receiveResponse; try { receiveResponse = enclave.receive(receiveRequest); @@ -144,23 +157,30 @@ public ValidationResult validatePrivateTransaction( } private SendRequest createSendRequest(final PrivateTransaction privateTransaction) { - final List privateFor = - privateTransaction.getPrivateFor().stream() - .map(BytesValues::asString) - .collect(Collectors.toList()); - - // FIXME: Orion should concatenate to and from - not it pantheon - if (privateFor.isEmpty()) { - privateFor.add(BytesValues.asString(privateTransaction.getPrivateFrom())); - } - final BytesValueRLPOutput bvrlp = new BytesValueRLPOutput(); privateTransaction.writeTo(bvrlp); - return new SendRequest( - Base64.getEncoder().encodeToString(bvrlp.encoded().extractArray()), - BytesValues.asString(privateTransaction.getPrivateFrom()), - privateFor); + if (privateTransaction.getPrivacyGroupId().isPresent()) { + return new SendRequestPantheon( + Base64.getEncoder().encodeToString(bvrlp.encoded().extractArray()), + enclavePublicKey, + BytesValues.asString(privateTransaction.getPrivacyGroupId().get())); + } else { + final List privateFor = + privateTransaction.getPrivateFor().get().stream() + .map(BytesValues::asString) + .collect(Collectors.toList()); + + // FIXME: orion should accept empty privateFor + if (privateFor.isEmpty()) { + privateFor.add(BytesValues.asString(privateTransaction.getPrivateFrom().get())); + } + + return new SendRequestLegacy( + Base64.getEncoder().encodeToString(bvrlp.encoded().extractArray()), + BytesValues.asString(privateTransaction.getPrivateFrom().get()), + privateFor); + } } public long getSenderNonce(final Address sender, final String privacyGroupId) { 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 index aa7a7b149a..260d6654af 100644 --- 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 @@ -20,6 +20,7 @@ import static tech.pegasys.pantheon.ethereum.mainnet.TransactionValidator.TransactionInvalidReason.INCORRECT_PRIVATE_NONCE; import static tech.pegasys.pantheon.ethereum.mainnet.TransactionValidator.TransactionInvalidReason.PRIVATE_NONCE_TOO_LOW; +import tech.pegasys.orion.testutil.OrionKeyUtils; import tech.pegasys.pantheon.crypto.SECP256K1; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.enclave.Enclave; @@ -107,6 +108,7 @@ public void setUp() throws Exception { mockEnclave(), Address.DEFAULT_PRIVACY, KEY_PAIR, + OrionKeyUtils.loadKey("orion_key_0.pub"), privateStateStorage, worldStateArchive); brokenPrivateTransactionHandler = @@ -114,19 +116,20 @@ public void setUp() throws Exception { brokenMockEnclave(), Address.DEFAULT_PRIVACY, KEY_PAIR, + OrionKeyUtils.loadKey("orion_key_0.pub"), privateStateStorage, worldStateArchive); } @Test - public void validTransactionThroughHandler() throws Exception { + public void validLegacyTransactionThroughHandler() throws Exception { - final PrivateTransaction transaction = buildPrivateTransaction(1); + final PrivateTransaction transaction = buildLegacyPrivateTransaction(1); final String enclaveKey = privateTransactionHandler.sendToOrion(transaction); final String privacyGroupId = - privateTransactionHandler.getPrivacyGroup(enclaveKey, transaction.getPrivateFrom()); + privateTransactionHandler.getPrivacyGroup(enclaveKey, transaction); final ValidationResult validationResult = privateTransactionHandler.validatePrivateTransaction(transaction, privacyGroupId); @@ -142,18 +145,40 @@ public void validTransactionThroughHandler() throws Exception { assertThat(markerTransaction.getValue()).isEqualTo(PUBLIC_TRANSACTION.getValue()); } + @Test + public void validPantheonTransactionThroughHandler() throws Exception { + + final PrivateTransaction transaction = buildPantheonPrivateTransaction(1); + + final String enclaveKey = privateTransactionHandler.sendToOrion(transaction); + + final ValidationResult validationResult = + privateTransactionHandler.validatePrivateTransaction( + transaction, transaction.getPrivacyGroupId().get().toString()); + + final Transaction markerTransaction = + privateTransactionHandler.createPrivacyMarkerTransaction(enclaveKey, transaction, 0L); + + assertThat(validationResult).isEqualTo(ValidationResult.valid()); + assertThat(markerTransaction.contractAddress()).isEqualTo(PUBLIC_TRANSACTION.contractAddress()); + assertThat(markerTransaction.getPayload()).isEqualTo(PUBLIC_TRANSACTION.getPayload()); + assertThat(markerTransaction.getNonce()).isEqualTo(PUBLIC_TRANSACTION.getNonce()); + assertThat(markerTransaction.getSender()).isEqualTo(PUBLIC_TRANSACTION.getSender()); + assertThat(markerTransaction.getValue()).isEqualTo(PUBLIC_TRANSACTION.getValue()); + } + @Test(expected = IOException.class) public void enclaveIsDownWhileHandling() throws Exception { - brokenPrivateTransactionHandler.sendToOrion(buildPrivateTransaction()); + brokenPrivateTransactionHandler.sendToOrion(buildLegacyPrivateTransaction()); } @Test public void nonceTooLowError() throws Exception { - final PrivateTransaction transaction = buildPrivateTransaction(0); + final PrivateTransaction transaction = buildLegacyPrivateTransaction(0); final String enclaveKey = privateTransactionHandler.sendToOrion(transaction); final String privacyGroupId = - privateTransactionHandler.getPrivacyGroup(enclaveKey, transaction.getPrivateFrom()); + privateTransactionHandler.getPrivacyGroup(enclaveKey, transaction); final ValidationResult validationResult = privateTransactionHandler.validatePrivateTransaction(transaction, privacyGroupId); assertThat(validationResult).isEqualTo(ValidationResult.invalid(PRIVATE_NONCE_TOO_LOW)); @@ -161,21 +186,40 @@ public void nonceTooLowError() throws Exception { @Test public void incorrectNonceError() throws Exception { - final PrivateTransaction transaction = buildPrivateTransaction(2); + final PrivateTransaction transaction = buildLegacyPrivateTransaction(2); final String enclaveKey = privateTransactionHandler.sendToOrion(transaction); final String privacyGroupId = - privateTransactionHandler.getPrivacyGroup(enclaveKey, transaction.getPrivateFrom()); + privateTransactionHandler.getPrivacyGroup(enclaveKey, transaction); final ValidationResult validationResult = privateTransactionHandler.validatePrivateTransaction(transaction, privacyGroupId); assertThat(validationResult).isEqualTo(ValidationResult.invalid(INCORRECT_PRIVATE_NONCE)); } - private static PrivateTransaction buildPrivateTransaction() { - return buildPrivateTransaction(0); + private static PrivateTransaction buildLegacyPrivateTransaction() { + return buildLegacyPrivateTransaction(0); + } + + private static PrivateTransaction buildLegacyPrivateTransaction(final long nonce) { + return buildPrivateTransaction(nonce) + .privateFrom( + BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8))) + .privateFor( + Lists.newArrayList( + BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8)), + BytesValue.wrap("Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs=".getBytes(UTF_8)))) + .signAndBuild(KEY_PAIR); } - private static PrivateTransaction buildPrivateTransaction(final long nonce) { + private static PrivateTransaction buildPantheonPrivateTransaction(final long nonce) { + + return buildPrivateTransaction(nonce) + .privacyGroupId( + BytesValue.wrap("DyAOiF/ynpc+JXa2YAGB0bCitSlOMNm+ShmB/7M6C4w=".getBytes(UTF_8))) + .signAndBuild(KEY_PAIR); + } + + private static PrivateTransaction.Builder buildPrivateTransaction(final long nonce) { return PrivateTransaction.builder() .nonce(nonce) .gasPrice(Wei.of(1000)) @@ -185,13 +229,6 @@ private static PrivateTransaction buildPrivateTransaction(final long nonce) { .payload(BytesValue.fromHexString("0x")) .sender(Address.fromHexString("0xfe3b557e8fb62b89f4916b721be55ceb828dbd73")) .chainId(BigInteger.valueOf(2018)) - .privateFrom( - BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8))) - .privateFor( - Lists.newArrayList( - BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8)), - BytesValue.wrap("Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs=".getBytes(UTF_8)))) - .restriction(Restriction.RESTRICTED) - .signAndBuild(KEY_PAIR); + .restriction(Restriction.RESTRICTED); } } diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionTest.java index 6d6ee675eb..a7eb06e175 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionTest.java @@ -50,6 +50,14 @@ public class PrivateTransactionTest { + "6e766966746a69697a706a52742b4854754642733d8a726573747269637465" + "64"; + private static final String VALID_PRIVATE_TRANSACTION_RLP_PRIVACY_GROUP = + "0xf8b7800182520894095e7baea6a6c7c4c2dfeb977efac326af552d87a0f" + + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + + "801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a3" + + "6649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53fa" + + "a07bd2c804ac4479414f69462f796e70632b4a5861325941474230624369745" + + "36c4f4d4e6d2b53686d422f374d364334773d8a72657374726963746564"; + private static final String VALID_SIGNED_PRIVATE_TRANSACTION_RLP = "0xf901a4808203e8832dc6c08080b8ef60806040523480156100105760008" + "0fd5b5060d08061001f6000396000f3fe60806040526004361060485763f" @@ -103,10 +111,38 @@ public class PrivateTransactionTest { BytesValue.fromHexString("0x"), Address.wrap(BytesValue.fromHexString("0x8411b12666f68ef74cace3615c9d5a377729d03f")), Optional.empty(), - BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8)), - Lists.newArrayList( - BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8)), - BytesValue.wrap("Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs=".getBytes(UTF_8))), + Optional.empty(), + Optional.of( + BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8))), + Optional.of( + Lists.newArrayList( + BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8)), + BytesValue.wrap("Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs=".getBytes(UTF_8)))), + Restriction.RESTRICTED); + + private static final PrivateTransaction VALID_PRIVATE_TRANSACTION_PRIVACY_GROUP = + 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")), + Optional.empty(), + Optional.of( + BytesValue.wrap("DyAOiF/ynpc+JXa2YAGB0bCitSlOMNm+ShmB/7M6C4w=".getBytes(UTF_8))), + Optional.empty(), + Optional.empty(), Restriction.RESTRICTED); private static final PrivateTransaction VALID_SIGNED_PRIVATE_TRANSACTION = @@ -186,6 +222,20 @@ public void testWriteTo() { assertEquals(VALID_PRIVATE_TRANSACTION_RLP, bvrlpo.encoded().toString()); } + @Test + public void testWriteTo_privacyGroup() { + BytesValueRLPOutput bvrlpo = new BytesValueRLPOutput(); + VALID_PRIVATE_TRANSACTION_PRIVACY_GROUP.writeTo(bvrlpo); + assertEquals(VALID_PRIVATE_TRANSACTION_RLP_PRIVACY_GROUP, bvrlpo.encoded().toString()); + } + + @Test + public void testWriteToWithLargeChainId() { + BytesValueRLPOutput bvrlpo = new BytesValueRLPOutput(); + VALID_SIGNED_PRIVATE_TRANSACTION_LARGE_CHAINID.writeTo(bvrlpo); + assertEquals(VALID_SIGNED_PRIVATE_TRANSACTION_LARGE_CHAINID_RLP, bvrlpo.encoded().toString()); + } + @Test public void testSignedWriteTo() { BytesValueRLPOutput bvrlpo = new BytesValueRLPOutput(); @@ -202,6 +252,16 @@ public void testReadFrom() { assertEquals(VALID_PRIVATE_TRANSACTION, p); } + @Test + public void testReadFrom_privacyGroup() { + PrivateTransaction p = + PrivateTransaction.readFrom( + new BytesValueRLPInput( + BytesValue.fromHexString(VALID_PRIVATE_TRANSACTION_RLP_PRIVACY_GROUP), false)); + + assertEquals(VALID_PRIVATE_TRANSACTION_PRIVACY_GROUP, p); + } + @Test public void testSignedReadFrom() { PrivateTransaction p = @@ -218,13 +278,6 @@ public void testReadFromInvalid() { new BytesValueRLPInput(BytesValue.fromHexString(INVALID_RLP), false)); } - @Test - public void testWriteToWithLargeChainId() { - BytesValueRLPOutput bvrlpo = new BytesValueRLPOutput(); - VALID_SIGNED_PRIVATE_TRANSACTION_LARGE_CHAINID.writeTo(bvrlpo); - assertEquals(VALID_SIGNED_PRIVATE_TRANSACTION_LARGE_CHAINID_RLP, bvrlpo.encoded().toString()); - } - @Test public void testReadFromWithLargeChainId() { PrivateTransaction p = @@ -235,4 +288,27 @@ public void testReadFromWithLargeChainId() { assertEquals(VALID_SIGNED_PRIVATE_TRANSACTION_LARGE_CHAINID, p); } + + @Test(expected = IllegalArgumentException.class) + public void testBuildInvalidPrivateTransactionThrowsException() { + PrivateTransaction.builder() + .nonce(0) + .gasPrice(Wei.of(1000)) + .gasLimit(3000000) + .to(Address.fromHexString("0x627306090abab3a6e1400e9345bc60c78a8bef57")) + .value(Wei.ZERO) + .payload(BytesValue.fromHexString("0x")) + .sender(Address.fromHexString("0xfe3b557e8fb62b89f4916b721be55ceb828dbd73")) + .chainId(BigInteger.valueOf(2018)) + .privacyGroupId( + BytesValue.wrap("DyAOiF/ynpc+JXa2YAGB0bCitSlOMNm+ShmB/7M6C4w=".getBytes(UTF_8))) + .privateFrom( + BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8))) + .privateFor( + Lists.newArrayList( + BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8)), + BytesValue.wrap("Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs=".getBytes(UTF_8)))) + .restriction(Restriction.RESTRICTED) + .build(); + } } 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 f3c74fef7b..abcd38f53c 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 @@ -95,9 +95,8 @@ public JsonRpcResponse response(final JsonRpcRequest request) { final String privacyGroupId; try { - privacyGroupId = - privateTransactionHandler.getPrivacyGroup( - enclaveKey, privateTransaction.getPrivateFrom()); + privacyGroupId = privateTransactionHandler.getPrivacyGroup(enclaveKey, privateTransaction); + } catch (final Exception e) { return new JsonRpcErrorResponse(request.getId(), convertEnclaveInvalidReason(e.getMessage())); } 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 9cc87fb233..b91f59d6fe 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 @@ -69,6 +69,14 @@ public class EeaSendRawTransactionTest { + "49644f6e766966746a69697a706a52742b4854754642733d8a72" + "657374726963746564"; + private static final String VALID_PRIVATE_TRANSACTION_RLP_PRIVACY_GROUP = + "0xf897800182520894095e7baea6a6c7c4c2dfeb977efac326af552d878" + + "0801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff75" + + "9b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b" + + "28ad43601b4ab949f53faa07bd2c804ac4479414f69462f796e70" + + "632b4a586132594147423062436974536c4f4d4e6d2b53686d422" + + "f374d364334773d8a72657374726963746564"; + private static final Transaction PUBLIC_TRANSACTION = new Transaction( 0L, @@ -182,7 +190,7 @@ public void validTransactionIsSentToTransactionPool() throws Exception { when(parameter.required(any(Object[].class), anyInt(), any())) .thenReturn(VALID_PRIVATE_TRANSACTION_RLP); when(privateTxHandler.sendToOrion(any(PrivateTransaction.class))).thenReturn(MOCK_ORION_KEY); - when(privateTxHandler.getPrivacyGroup(any(String.class), any(BytesValue.class))) + when(privateTxHandler.getPrivacyGroup(any(String.class), any(PrivateTransaction.class))) .thenReturn(MOCK_PRIVACY_GROUP); when(privateTxHandler.validatePrivateTransaction( any(PrivateTransaction.class), any(String.class))) @@ -205,7 +213,46 @@ public void validTransactionIsSentToTransactionPool() throws Exception { assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse); verify(privateTxHandler).sendToOrion(any(PrivateTransaction.class)); - verify(privateTxHandler).getPrivacyGroup(any(String.class), any(BytesValue.class)); + verify(privateTxHandler).getPrivacyGroup(any(String.class), any(PrivateTransaction.class)); + verify(privateTxHandler) + .validatePrivateTransaction(any(PrivateTransaction.class), any(String.class)); + verify(privateTxHandler) + .createPrivacyMarkerTransaction( + any(String.class), any(PrivateTransaction.class), any(Long.class)); + verify(transactionPool).addLocalTransaction(any(Transaction.class)); + } + + @Test + public void validTransactionPrivayGroupIsSentToTransactionPool() throws Exception { + when(parameter.required(any(Object[].class), anyInt(), any())) + .thenReturn(VALID_PRIVATE_TRANSACTION_RLP_PRIVACY_GROUP); + when(privateTxHandler.sendToOrion(any(PrivateTransaction.class))).thenReturn(MOCK_ORION_KEY); + when(privateTxHandler.getPrivacyGroup(any(String.class), any(PrivateTransaction.class))) + .thenReturn(MOCK_PRIVACY_GROUP); + when(privateTxHandler.validatePrivateTransaction( + any(PrivateTransaction.class), any(String.class))) + .thenReturn(ValidationResult.valid()); + when(privateTxHandler.createPrivacyMarkerTransaction( + any(String.class), any(PrivateTransaction.class), any(Long.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_PRIVATE_TRANSACTION_RLP_PRIVACY_GROUP}); + + final JsonRpcResponse expectedResponse = + new JsonRpcSuccessResponse( + request.getId(), "0x221e930a2c18d91fca4d509eaa3512f3e01fef266f660e32473de67474b36c15"); + + final JsonRpcResponse actualResponse = method.response(request); + + assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse); + verify(privateTxHandler).sendToOrion(any(PrivateTransaction.class)); + verify(privateTxHandler).getPrivacyGroup(any(String.class), any(PrivateTransaction.class)); verify(privateTxHandler) .validatePrivateTransaction(any(PrivateTransaction.class), any(String.class)); verify(privateTxHandler) @@ -283,7 +330,7 @@ private void verifyErrorForInvalidTransaction( when(parameter.required(any(Object[].class), anyInt(), any())) .thenReturn(VALID_PRIVATE_TRANSACTION_RLP); when(privateTxHandler.sendToOrion(any(PrivateTransaction.class))).thenReturn(MOCK_ORION_KEY); - when(privateTxHandler.getPrivacyGroup(any(String.class), any(BytesValue.class))) + when(privateTxHandler.getPrivacyGroup(any(String.class), any(PrivateTransaction.class))) .thenReturn(MOCK_PRIVACY_GROUP); when(privateTxHandler.validatePrivateTransaction( any(PrivateTransaction.class), any(String.class))) @@ -305,7 +352,7 @@ private void verifyErrorForInvalidTransaction( assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse); verify(privateTxHandler).sendToOrion(any(PrivateTransaction.class)); - verify(privateTxHandler).getPrivacyGroup(any(String.class), any(BytesValue.class)); + verify(privateTxHandler).getPrivacyGroup(any(String.class), any(PrivateTransaction.class)); verify(privateTxHandler) .validatePrivateTransaction(any(PrivateTransaction.class), any(String.class)); verify(privateTxHandler) diff --git a/testutil/src/main/java/tech/pegasys/orion/testutil/OrionKeyGenerator.java b/testutil/src/main/java/tech/pegasys/orion/testutil/OrionKeyUtils.java similarity index 66% rename from testutil/src/main/java/tech/pegasys/orion/testutil/OrionKeyGenerator.java rename to testutil/src/main/java/tech/pegasys/orion/testutil/OrionKeyUtils.java index 3edea19681..b3c02ac724 100644 --- a/testutil/src/main/java/tech/pegasys/orion/testutil/OrionKeyGenerator.java +++ b/testutil/src/main/java/tech/pegasys/orion/testutil/OrionKeyUtils.java @@ -12,6 +12,11 @@ */ package tech.pegasys.orion.testutil; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; @@ -23,9 +28,25 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -public class OrionKeyGenerator { +public class OrionKeyUtils { private static final Logger LOG = LogManager.getLogger(); + /** + * Utility method to load the enclave public key. Possible input values are the names of the *.pub + * files in the resources folder. + * + * @param keyFileName the name of the file containing the enclave public key + * @return the enclave public key stored in that file + * @throws IOException throws if key not found + */ + public static String loadKey(final String keyFileName) throws IOException { + InputStream is = OrionKeyUtils.class.getResourceAsStream("/" + keyFileName); + InputStreamReader streamReader = new InputStreamReader(is, StandardCharsets.UTF_8); + try (BufferedReader reader = new BufferedReader(streamReader)) { + return reader.readLine(); + } + } + public static KeyPair generateKeys() throws NoSuchAlgorithmException { final KeyPair keyPair = KeyPairGenerator.getInstance("Ed25519").generateKeyPair(); final PublicKey pubKey = keyPair.getPublic();