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