mirror of https://github.com/hyperledger/besu
refactor: EeaSendRawTransaction isolate send raw on/off chain (#2283)
* refactor: isolate send raw on/off chain Signed-off-by: Antony Denyer <git@antonydenyer.co.uk> * Move responsibility of checking restriction type into JsonRpcMethod Signed-off-by: Antony Denyer <git@antonydenyer.co.uk> * Refactor: Make use of privacy vs private consistent Rename s/privacyMarkerTransaction/privateMarkerTransaction/g Signed-off-by: Antony Denyer <git@antonydenyer.co.uk>pull/2392/head
parent
b81a481a42
commit
51287459ab
@ -0,0 +1,85 @@ |
||||
/* |
||||
* Copyright ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.eea; |
||||
|
||||
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.PRIVATE_FROM_DOES_NOT_MATCH_ENCLAVE_PUBLIC_KEY; |
||||
import static org.hyperledger.besu.ethereum.privacy.PrivacyGroupUtil.findOffchainPrivacyGroup; |
||||
|
||||
import org.hyperledger.besu.enclave.types.PrivacyGroup; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; |
||||
import org.hyperledger.besu.ethereum.core.Address; |
||||
import org.hyperledger.besu.ethereum.core.Transaction; |
||||
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; |
||||
import org.hyperledger.besu.ethereum.mainnet.ValidationResult; |
||||
import org.hyperledger.besu.ethereum.privacy.PrivacyController; |
||||
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction; |
||||
import org.hyperledger.besu.ethereum.privacy.Restriction; |
||||
import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; |
||||
|
||||
import java.util.Optional; |
||||
|
||||
import io.vertx.ext.auth.User; |
||||
import org.apache.tuweni.bytes.Bytes; |
||||
|
||||
public class RestrictedOffChainEeaSendRawTransaction extends AbstractEeaSendRawTransaction { |
||||
|
||||
final PrivacyController privacyController; |
||||
private final EnclavePublicKeyProvider enclavePublicKeyProvider; |
||||
|
||||
public RestrictedOffChainEeaSendRawTransaction( |
||||
final TransactionPool transactionPool, |
||||
final PrivacyController privacyController, |
||||
final EnclavePublicKeyProvider enclavePublicKeyProvider) { |
||||
super(transactionPool); |
||||
this.privacyController = privacyController; |
||||
this.enclavePublicKeyProvider = enclavePublicKeyProvider; |
||||
} |
||||
|
||||
@Override |
||||
protected ValidationResult<TransactionInvalidReason> validatePrivateTransaction( |
||||
final PrivateTransaction privateTransaction, final Optional<User> user) { |
||||
|
||||
if (!privateTransaction.getRestriction().equals(Restriction.RESTRICTED)) { |
||||
return ValidationResult.invalid( |
||||
TransactionInvalidReason.PRIVATE_UNIMPLEMENTED_TRANSACTION_TYPE); |
||||
} |
||||
|
||||
final String enclavePublicKey = enclavePublicKeyProvider.getEnclaveKey(user); |
||||
|
||||
if (!privateTransaction.getPrivateFrom().equals(Bytes.fromBase64String(enclavePublicKey))) { |
||||
throw new JsonRpcErrorResponseException(PRIVATE_FROM_DOES_NOT_MATCH_ENCLAVE_PUBLIC_KEY); |
||||
} |
||||
|
||||
return privacyController.validatePrivateTransaction( |
||||
privateTransaction, enclavePublicKeyProvider.getEnclaveKey(user)); |
||||
} |
||||
|
||||
@Override |
||||
protected Transaction createPrivateMarkerTransaction( |
||||
final PrivateTransaction privateTransaction, final Optional<User> user) { |
||||
|
||||
final Optional<PrivacyGroup> maybePrivacyGroup = |
||||
findOffchainPrivacyGroup( |
||||
privacyController, |
||||
privateTransaction.getPrivacyGroupId(), |
||||
enclavePublicKeyProvider.getEnclaveKey(user)); |
||||
|
||||
final String privateTransactionLookupId = |
||||
privacyController.sendTransaction( |
||||
privateTransaction, enclavePublicKeyProvider.getEnclaveKey(user), maybePrivacyGroup); |
||||
return privacyController.createPrivateMarkerTransaction( |
||||
privateTransactionLookupId, privateTransaction, Address.DEFAULT_PRIVACY); |
||||
} |
||||
} |
@ -0,0 +1,146 @@ |
||||
/* |
||||
* Copyright ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.eea; |
||||
|
||||
import org.hyperledger.besu.crypto.KeyPair; |
||||
import org.hyperledger.besu.crypto.SignatureAlgorithm; |
||||
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; |
||||
import org.hyperledger.besu.ethereum.core.Address; |
||||
import org.hyperledger.besu.ethereum.core.Transaction; |
||||
import org.hyperledger.besu.ethereum.core.Wei; |
||||
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; |
||||
import org.hyperledger.besu.ethereum.privacy.PrivacyController; |
||||
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction; |
||||
import org.hyperledger.besu.ethereum.privacy.Restriction; |
||||
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; |
||||
|
||||
import java.math.BigInteger; |
||||
import java.util.List; |
||||
import java.util.Optional; |
||||
|
||||
import com.google.common.base.Supplier; |
||||
import com.google.common.base.Suppliers; |
||||
import org.apache.tuweni.bytes.Bytes; |
||||
import org.mockito.Mock; |
||||
|
||||
public class BaseEeaSendRawTransaction { |
||||
|
||||
final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM = |
||||
Suppliers.memoize(SignatureAlgorithmFactory::getInstance); |
||||
|
||||
final Transaction PUBLIC_TRANSACTION = |
||||
new Transaction( |
||||
0L, |
||||
Wei.of(1), |
||||
21000L, |
||||
Optional.of( |
||||
Address.wrap(Bytes.fromHexString("0x095e7baea6a6c7c4c2dfeb977efac326af552d87"))), |
||||
Wei.ZERO, |
||||
SIGNATURE_ALGORITHM |
||||
.get() |
||||
.createSignature( |
||||
new BigInteger( |
||||
"32886959230931919120748662916110619501838190146643992583529828535682419954515"), |
||||
new BigInteger( |
||||
"14473701025599600909210599917245952381483216609124029382871721729679842002948"), |
||||
Byte.parseByte("0")), |
||||
Bytes.fromHexString("0x"), |
||||
Address.wrap(Bytes.fromHexString("0x8411b12666f68ef74cace3615c9d5a377729d03f")), |
||||
Optional.empty()); |
||||
|
||||
final JsonRpcRequestContext validPrivateForTransactionRequest = |
||||
new JsonRpcRequestContext( |
||||
new JsonRpcRequest( |
||||
"2.0", "eea_sendRawTransaction", new String[] {validPrivateForTransaction()})); |
||||
|
||||
final JsonRpcRequestContext validPrivacyGroupTransactionRequest = |
||||
new JsonRpcRequestContext( |
||||
new JsonRpcRequest( |
||||
"2.0", |
||||
"eea_sendRawTransaction", |
||||
new String[] {validPrivatePrivacyGroupTransaction(Restriction.RESTRICTED)})); |
||||
|
||||
final JsonRpcRequestContext validUnrestrictedPrivacyGroupTransactionRequest = |
||||
new JsonRpcRequestContext( |
||||
new JsonRpcRequest( |
||||
"2.0", |
||||
"eea_sendRawTransaction", |
||||
new String[] {validPrivatePrivacyGroupTransaction(Restriction.UNRESTRICTED)})); |
||||
|
||||
final JsonRpcRequestContext validUnsuportedPrivacyGroupTransactionRequest = |
||||
new JsonRpcRequestContext( |
||||
new JsonRpcRequest( |
||||
"2.0", |
||||
"eea_sendRawTransaction", |
||||
new String[] {validPrivatePrivacyGroupTransaction(Restriction.UNSUPPORTED)})); |
||||
|
||||
@Mock TransactionPool transactionPool; |
||||
@Mock PrivacyController privacyController; |
||||
|
||||
private String validPrivateForTransaction() { |
||||
final PrivateTransaction.Builder privateTransactionBuilder = |
||||
PrivateTransaction.builder() |
||||
.nonce(0) |
||||
.gasPrice(Wei.of(1)) |
||||
.gasLimit(21000) |
||||
.value(Wei.ZERO) |
||||
.payload(Bytes.EMPTY) |
||||
.to(Address.fromHexString("0x095e7baea6a6c7c4c2dfeb977efac326af552d87")) |
||||
.chainId(BigInteger.ONE) |
||||
.privateFrom(Bytes.fromBase64String("S28yYlZxRCtuTmxOWUw1RUU3eTNJZE9udmlmdGppaXp=")) |
||||
.privateFor( |
||||
List.of( |
||||
Bytes.fromBase64String("S28yYlZxRCtuTmxOWUw1RUU3eTNJZE9udmlmdGppaXp="), |
||||
Bytes.fromBase64String("QTFhVnRNeExDVUhtQlZIWG9aenpCZ1BiVy93ajVheER="))) |
||||
.restriction(Restriction.RESTRICTED); |
||||
return rlpEncodeTransaction(privateTransactionBuilder); |
||||
} |
||||
|
||||
private String validPrivatePrivacyGroupTransaction(final Restriction restriction) { |
||||
final PrivateTransaction.Builder privateTransactionBuilder = |
||||
PrivateTransaction.builder() |
||||
.nonce(0) |
||||
.gasPrice(Wei.of(1)) |
||||
.gasLimit(21000) |
||||
.value(Wei.ZERO) |
||||
.payload(Bytes.EMPTY) |
||||
.to(Address.fromHexString("0x095e7baea6a6c7c4c2dfeb977efac326af552d87")) |
||||
.chainId(BigInteger.ONE) |
||||
.privateFrom(Bytes.fromBase64String("S28yYlZxRCtuTmxOWUw1RUU3eTNJZE9udmlmdGppaXp=")) |
||||
.privacyGroupId(Bytes.fromBase64String("DyAOiF/ynpc+JXa2YAGB0bCitSlOMNm+ShmB/7M6C4w=")) |
||||
.restriction(restriction); |
||||
return rlpEncodeTransaction(privateTransactionBuilder); |
||||
} |
||||
|
||||
private String rlpEncodeTransaction(final PrivateTransaction.Builder privateTransactionBuilder) { |
||||
final KeyPair keyPair = |
||||
SIGNATURE_ALGORITHM |
||||
.get() |
||||
.createKeyPair( |
||||
SIGNATURE_ALGORITHM |
||||
.get() |
||||
.createPrivateKey( |
||||
new BigInteger( |
||||
"8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", |
||||
16))); |
||||
|
||||
final PrivateTransaction privateTransaction = privateTransactionBuilder.signAndBuild(keyPair); |
||||
final BytesValueRLPOutput bvrlp = new BytesValueRLPOutput(); |
||||
privateTransaction.writeTo(bvrlp); |
||||
return bvrlp.encoded().toHexString(); |
||||
} |
||||
} |
@ -1,140 +0,0 @@ |
||||
/* |
||||
* Copyright ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.eea; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.ArgumentMatchers.any; |
||||
import static org.mockito.ArgumentMatchers.eq; |
||||
import static org.mockito.Mockito.verify; |
||||
import static org.mockito.Mockito.when; |
||||
|
||||
import org.hyperledger.besu.enclave.types.PrivacyGroup; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; |
||||
import org.hyperledger.besu.ethereum.core.Address; |
||||
import org.hyperledger.besu.ethereum.core.Transaction; |
||||
import org.hyperledger.besu.ethereum.mainnet.ValidationResult; |
||||
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.Optional; |
||||
|
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
import org.mockito.junit.MockitoJUnitRunner; |
||||
|
||||
@RunWith(MockitoJUnitRunner.class) |
||||
public class OnChainEeaSendRawTransactionTest extends EeaSendRawTransactionTest { |
||||
|
||||
@Test |
||||
public void validOnChainTransactionPrivacyGroupIsSentToTransactionPool() { |
||||
method = |
||||
new OnChainEeaSendRawTransaction( |
||||
transactionPool, privacyController, enclavePublicKeyProvider); |
||||
|
||||
when(privacyController.sendTransaction(any(PrivateTransaction.class), any(), any())) |
||||
.thenReturn(MOCK_ORION_KEY); |
||||
when(privacyController.validatePrivateTransaction( |
||||
any(PrivateTransaction.class), any(String.class))) |
||||
.thenReturn(ValidationResult.valid()); |
||||
final Optional<PrivacyGroup> optionalPrivacyGroup = |
||||
Optional.of( |
||||
new PrivacyGroup( |
||||
"", PrivacyGroup.Type.ONCHAIN, "", "", Arrays.asList(ENCLAVE_PUBLIC_KEY))); |
||||
when(privacyController.findOnChainPrivacyGroupAndAddNewMembers(any(), any(), any())) |
||||
.thenReturn(optionalPrivacyGroup); |
||||
when(privacyController.createPrivacyMarkerTransaction( |
||||
any(String.class), any(PrivateTransaction.class), any(Address.class))) |
||||
.thenReturn(PUBLIC_TRANSACTION); |
||||
when(transactionPool.addLocalTransaction(any(Transaction.class))) |
||||
.thenReturn(ValidationResult.valid()); |
||||
|
||||
final JsonRpcRequestContext request = |
||||
new JsonRpcRequestContext( |
||||
new JsonRpcRequest( |
||||
"2.0", |
||||
"eea_sendRawTransaction", |
||||
new String[] {VALID_PRIVATE_TRANSACTION_RLP_PRIVACY_GROUP})); |
||||
|
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcSuccessResponse( |
||||
request.getRequest().getId(), |
||||
"0x221e930a2c18d91fca4d509eaa3512f3e01fef266f660e32473de67474b36c15"); |
||||
|
||||
final JsonRpcResponse actualResponse = method.response(request); |
||||
|
||||
assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse); |
||||
verify(privacyController).sendTransaction(any(PrivateTransaction.class), any(), any()); |
||||
verify(privacyController) |
||||
.validatePrivateTransaction(any(PrivateTransaction.class), any(String.class)); |
||||
verify(privacyController) |
||||
.createPrivacyMarkerTransaction( |
||||
any(String.class), any(PrivateTransaction.class), eq(Address.ONCHAIN_PRIVACY)); |
||||
verify(transactionPool).addLocalTransaction(any(Transaction.class)); |
||||
} |
||||
|
||||
@Test |
||||
public void transactionFailsForLegacyPrivateTransaction() { |
||||
method = |
||||
new OnChainEeaSendRawTransaction( |
||||
transactionPool, privacyController, enclavePublicKeyProvider); |
||||
|
||||
final JsonRpcRequestContext request = getJsonRpcRequestContext(); |
||||
|
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcErrorResponse( |
||||
request.getRequest().getId(), JsonRpcError.ONCHAIN_PRIVACY_GROUP_ID_NOT_AVAILABLE); |
||||
|
||||
final JsonRpcResponse actualResponse = method.response(request); |
||||
|
||||
assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse); |
||||
} |
||||
|
||||
private JsonRpcRequestContext getJsonRpcRequestContext() { |
||||
return new JsonRpcRequestContext( |
||||
new JsonRpcRequest( |
||||
"2.0", "eea_sendRawTransaction", new String[] {VALID_LEGACY_PRIVATE_TRANSACTION_RLP}), |
||||
user); |
||||
} |
||||
|
||||
@Test |
||||
public void offChainPrivacyGroupTransactionFailsWhenOnchainPrivacyGroupFeatureIsEnabled() { |
||||
method = |
||||
new OnChainEeaSendRawTransaction( |
||||
transactionPool, privacyController, enclavePublicKeyProvider); |
||||
|
||||
when(privacyController.findOnChainPrivacyGroupAndAddNewMembers(any(), any(), any())) |
||||
.thenReturn(Optional.empty()); |
||||
|
||||
final JsonRpcRequestContext request = |
||||
new JsonRpcRequestContext( |
||||
new JsonRpcRequest( |
||||
"2.0", |
||||
"eea_sendRawTransaction", |
||||
new String[] {VALID_PRIVATE_TRANSACTION_RLP_PRIVACY_GROUP})); |
||||
|
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcErrorResponse( |
||||
request.getRequest().getId(), JsonRpcError.ONCHAIN_PRIVACY_GROUP_DOES_NOT_EXIST); |
||||
|
||||
final JsonRpcResponse actualResponse = method.response(request); |
||||
|
||||
assertThat(actualResponse).isEqualToComparingFieldByField(expectedResponse); |
||||
} |
||||
} |
@ -0,0 +1,132 @@ |
||||
/* |
||||
* Copyright ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.eea; |
||||
|
||||
import static java.util.Collections.singletonList; |
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.ArgumentMatchers.any; |
||||
import static org.mockito.ArgumentMatchers.eq; |
||||
import static org.mockito.Mockito.verify; |
||||
import static org.mockito.Mockito.when; |
||||
|
||||
import org.hyperledger.besu.enclave.types.PrivacyGroup; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; |
||||
import org.hyperledger.besu.ethereum.core.Address; |
||||
import org.hyperledger.besu.ethereum.mainnet.ValidationResult; |
||||
|
||||
import java.util.Optional; |
||||
|
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
import org.mockito.junit.MockitoJUnitRunner; |
||||
|
||||
@RunWith(MockitoJUnitRunner.class) |
||||
public class RestrictedOffChainEeaSendRawTransactionTest extends BaseEeaSendRawTransaction { |
||||
static final String ENCLAVE_PUBLIC_KEY = "S28yYlZxRCtuTmxOWUw1RUU3eTNJZE9udmlmdGppaXo="; |
||||
final String MOCK_ORION_KEY = ""; |
||||
|
||||
final EnclavePublicKeyProvider enclavePublicKeyProvider = (user) -> ENCLAVE_PUBLIC_KEY; |
||||
|
||||
RestrictedOffChainEeaSendRawTransaction method; |
||||
|
||||
@Before |
||||
public void before() { |
||||
method = |
||||
new RestrictedOffChainEeaSendRawTransaction( |
||||
transactionPool, privacyController, enclavePublicKeyProvider); |
||||
} |
||||
|
||||
@Test |
||||
public void validLegacyTransactionIsSentToTransactionPool() { |
||||
when(privacyController.sendTransaction(any(), any(), any())).thenReturn(MOCK_ORION_KEY); |
||||
when(privacyController.validatePrivateTransaction(any(), any())) |
||||
.thenReturn(ValidationResult.valid()); |
||||
when(privacyController.createPrivateMarkerTransaction(any(), any(), any())) |
||||
.thenReturn(PUBLIC_TRANSACTION); |
||||
when(transactionPool.addLocalTransaction(any())).thenReturn(ValidationResult.valid()); |
||||
|
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcSuccessResponse( |
||||
validPrivateForTransactionRequest.getRequest().getId(), |
||||
"0x221e930a2c18d91fca4d509eaa3512f3e01fef266f660e32473de67474b36c15"); |
||||
|
||||
final JsonRpcResponse actualResponse = method.response(validPrivateForTransactionRequest); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
verify(transactionPool).addLocalTransaction(PUBLIC_TRANSACTION); |
||||
verify(privacyController) |
||||
.createPrivateMarkerTransaction(any(), any(), eq(Address.DEFAULT_PRIVACY)); |
||||
} |
||||
|
||||
@Test |
||||
public void validPantheonPrivacyGroupTransactionIsSentToTransactionPool() { |
||||
when(privacyController.validatePrivateTransaction(any(), any())) |
||||
.thenReturn(ValidationResult.valid()); |
||||
|
||||
Optional<PrivacyGroup> pantheonPrivacyGroup = |
||||
Optional.of( |
||||
new PrivacyGroup( |
||||
"", PrivacyGroup.Type.PANTHEON, "", "", singletonList(ENCLAVE_PUBLIC_KEY))); |
||||
|
||||
when(privacyController.findOffChainPrivacyGroupByGroupId(any(), any())) |
||||
.thenReturn(pantheonPrivacyGroup); |
||||
when(privacyController.createPrivateMarkerTransaction(any(), any(), any())) |
||||
.thenReturn(PUBLIC_TRANSACTION); |
||||
when(transactionPool.addLocalTransaction(any())).thenReturn(ValidationResult.valid()); |
||||
|
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcSuccessResponse( |
||||
validPrivacyGroupTransactionRequest.getRequest().getId(), |
||||
"0x221e930a2c18d91fca4d509eaa3512f3e01fef266f660e32473de67474b36c15"); |
||||
|
||||
final JsonRpcResponse actualResponse = method.response(validPrivacyGroupTransactionRequest); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
verify(transactionPool).addLocalTransaction(PUBLIC_TRANSACTION); |
||||
verify(privacyController) |
||||
.createPrivateMarkerTransaction(any(), any(), eq(Address.DEFAULT_PRIVACY)); |
||||
} |
||||
|
||||
@Test |
||||
public void |
||||
transactionWithUnrestrictedTransactionTypeShouldReturnUnimplementedTransactionTypeError() { |
||||
final JsonRpcResponse actualResponse = |
||||
method.response(validUnrestrictedPrivacyGroupTransactionRequest); |
||||
|
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcErrorResponse( |
||||
validPrivacyGroupTransactionRequest.getRequest().getId(), JsonRpcError.INVALID_PARAMS); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
} |
||||
|
||||
@Test |
||||
public void |
||||
transactionWithUnsupportedTransactionTypeShouldReturnUnimplementedTransactionTypeError() { |
||||
final JsonRpcResponse actualResponse = |
||||
method.response(validUnsuportedPrivacyGroupTransactionRequest); |
||||
|
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcErrorResponse( |
||||
validPrivacyGroupTransactionRequest.getRequest().getId(), JsonRpcError.INVALID_PARAMS); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
} |
||||
} |
@ -0,0 +1,175 @@ |
||||
/* |
||||
* Copyright ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.eea; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.ArgumentMatchers.any; |
||||
import static org.mockito.ArgumentMatchers.eq; |
||||
import static org.mockito.Mockito.verify; |
||||
import static org.mockito.Mockito.when; |
||||
|
||||
import org.hyperledger.besu.enclave.types.PrivacyGroup; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; |
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; |
||||
import org.hyperledger.besu.ethereum.core.Address; |
||||
import org.hyperledger.besu.ethereum.core.Transaction; |
||||
import org.hyperledger.besu.ethereum.mainnet.ValidationResult; |
||||
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.Optional; |
||||
|
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
import org.mockito.junit.MockitoJUnitRunner; |
||||
|
||||
@RunWith(MockitoJUnitRunner.class) |
||||
public class RestrictedOnChainEeaSendRawTransactionTest extends BaseEeaSendRawTransaction { |
||||
static final String ENCLAVE_PUBLIC_KEY = "S28yYlZxRCtuTmxOWUw1RUU3eTNJZE9udmlmdGppaXo="; |
||||
final String MOCK_ORION_KEY = ""; |
||||
|
||||
final EnclavePublicKeyProvider enclavePublicKeyProvider = (user) -> ENCLAVE_PUBLIC_KEY; |
||||
|
||||
RestrictedOnChainEeaSendRawTransaction method; |
||||
|
||||
@Before |
||||
public void before() { |
||||
method = |
||||
new RestrictedOnChainEeaSendRawTransaction( |
||||
transactionPool, privacyController, enclavePublicKeyProvider); |
||||
} |
||||
|
||||
@Test |
||||
public void validOnChainTransactionPrivacyGroupIsSentToTransactionPool() { |
||||
when(privacyController.sendTransaction(any(), any(), any())).thenReturn(MOCK_ORION_KEY); |
||||
when(privacyController.validatePrivateTransaction(any(), any())) |
||||
.thenReturn(ValidationResult.valid()); |
||||
when(privacyController.createPrivateMarkerTransaction( |
||||
any(String.class), any(PrivateTransaction.class), any(Address.class))) |
||||
.thenReturn(PUBLIC_TRANSACTION); |
||||
when(transactionPool.addLocalTransaction(any(Transaction.class))) |
||||
.thenReturn(ValidationResult.valid()); |
||||
|
||||
final Optional<PrivacyGroup> onChainPrivacyGroup = |
||||
Optional.of( |
||||
new PrivacyGroup( |
||||
"", PrivacyGroup.Type.ONCHAIN, "", "", Arrays.asList(ENCLAVE_PUBLIC_KEY))); |
||||
|
||||
when(privacyController.findOnChainPrivacyGroupAndAddNewMembers(any(), any(), any())) |
||||
.thenReturn(onChainPrivacyGroup); |
||||
|
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcSuccessResponse( |
||||
validPrivacyGroupTransactionRequest.getRequest().getId(), |
||||
"0x221e930a2c18d91fca4d509eaa3512f3e01fef266f660e32473de67474b36c15"); |
||||
|
||||
final JsonRpcResponse actualResponse = method.response(validPrivacyGroupTransactionRequest); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
verify(transactionPool).addLocalTransaction(PUBLIC_TRANSACTION); |
||||
verify(privacyController) |
||||
.createPrivateMarkerTransaction(any(), any(), eq(Address.ONCHAIN_PRIVACY)); |
||||
} |
||||
|
||||
@Test |
||||
public void transactionFailsForLegacyPrivateTransaction() { |
||||
when(privacyController.validatePrivateTransaction(any(), any())) |
||||
.thenReturn(ValidationResult.valid()); |
||||
|
||||
method = |
||||
new RestrictedOnChainEeaSendRawTransaction( |
||||
transactionPool, privacyController, enclavePublicKeyProvider); |
||||
|
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcErrorResponse( |
||||
validPrivateForTransactionRequest.getRequest().getId(), |
||||
JsonRpcError.ONCHAIN_PRIVACY_GROUP_ID_NOT_AVAILABLE); |
||||
|
||||
final JsonRpcResponse actualResponse = method.response(validPrivateForTransactionRequest); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
} |
||||
|
||||
@Test |
||||
public void offChainPrivacyGroupTransactionFailsWhenOnchainPrivacyGroupFeatureIsEnabled() { |
||||
when(privacyController.validatePrivateTransaction(any(), any())) |
||||
.thenReturn(ValidationResult.valid()); |
||||
|
||||
method = |
||||
new RestrictedOnChainEeaSendRawTransaction( |
||||
transactionPool, privacyController, enclavePublicKeyProvider); |
||||
|
||||
when(privacyController.findOnChainPrivacyGroupAndAddNewMembers(any(), any(), any())) |
||||
.thenReturn(Optional.empty()); |
||||
|
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcErrorResponse( |
||||
validPrivacyGroupTransactionRequest.getRequest().getId(), |
||||
JsonRpcError.ONCHAIN_PRIVACY_GROUP_DOES_NOT_EXIST); |
||||
|
||||
final JsonRpcResponse actualResponse = method.response(validPrivacyGroupTransactionRequest); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
} |
||||
|
||||
@Test |
||||
public void onChainPrivacyGroupTransactionFailsWhenGroupDoesNotExist() { |
||||
when(privacyController.validatePrivateTransaction(any(), any())) |
||||
.thenReturn(ValidationResult.valid()); |
||||
|
||||
method = |
||||
new RestrictedOnChainEeaSendRawTransaction( |
||||
transactionPool, privacyController, enclavePublicKeyProvider); |
||||
|
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcErrorResponse( |
||||
validPrivacyGroupTransactionRequest.getRequest().getId(), |
||||
JsonRpcError.ONCHAIN_PRIVACY_GROUP_DOES_NOT_EXIST); |
||||
|
||||
final JsonRpcResponse actualResponse = method.response(validPrivacyGroupTransactionRequest); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
} |
||||
|
||||
@Test |
||||
public void |
||||
transactionWithUnrestrictedTransactionTypeShouldReturnUnimplementedTransactionTypeError() { |
||||
final JsonRpcResponse actualResponse = |
||||
method.response(validUnrestrictedPrivacyGroupTransactionRequest); |
||||
|
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcErrorResponse( |
||||
validPrivacyGroupTransactionRequest.getRequest().getId(), JsonRpcError.INVALID_PARAMS); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
} |
||||
|
||||
@Test |
||||
public void |
||||
transactionWithUnsupportedTransactionTypeShouldReturnUnimplementedTransactionTypeError() { |
||||
final JsonRpcResponse actualResponse = |
||||
method.response(validUnsuportedPrivacyGroupTransactionRequest); |
||||
|
||||
final JsonRpcResponse expectedResponse = |
||||
new JsonRpcErrorResponse( |
||||
validPrivacyGroupTransactionRequest.getRequest().getId(), JsonRpcError.INVALID_PARAMS); |
||||
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); |
||||
} |
||||
} |
Loading…
Reference in new issue