Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate private transaction before sending to enclave #356

Merged
merged 30 commits into from
Feb 10, 2020
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
70c6100
validate private transactions before sending to enclave
jframe Jan 24, 2020
0269a17
spotless
jframe Jan 24, 2020
c7eeecc
fix PrivDistributeRawTransaction UT
jframe Jan 24, 2020
06f02f5
wip
jframe Jan 28, 2020
08f8fb3
unit tests
jframe Jan 30, 2020
2f3ee18
Merge branch 'master' into validate_private_tx_before_enclave
jframe Jan 30, 2020
d6b7217
small refactoring changes
jframe Jan 30, 2020
e8129df
privateTransactionValidator tests
jframe Jan 30, 2020
f9e321f
renaming some methods
jframe Jan 30, 2020
8aa4f99
private send tx ut
jframe Feb 3, 2020
c0f0b58
cleanup ut
jframe Feb 3, 2020
e2c4c8b
rename uts
jframe Feb 3, 2020
ffb9131
Merge branch 'master' into validate_private_tx_before_enclave
jframe Feb 3, 2020
15d0c9b
add license header
jframe Feb 3, 2020
2137620
fix ut: wip
jframe Feb 3, 2020
265b38a
fix ut
jframe Feb 3, 2020
7e18b95
remove privacy send transaction helper class
jframe Feb 4, 2020
237b109
spotless
jframe Feb 4, 2020
3c481bd
fix unit test
jframe Feb 4, 2020
c137981
besu implementation of eea privacy group generation
jframe Feb 4, 2020
9fe45d5
license header & finals
jframe Feb 4, 2020
9d3fec5
fix bug in privacy group duplicate handling
jframe Feb 4, 2020
c886a63
rename method
jframe Feb 5, 2020
3dc38aa
rename test variables
jframe Feb 6, 2020
7714111
reuse request id in rpcs
jframe Feb 6, 2020
e8a978d
include transaction hash on debug logs
jframe Feb 6, 2020
cbd1c21
move privacyGroup calculation onto PrivateTransaction
jframe Feb 6, 2020
adfdc6c
Merge branch 'master' into validate_private_tx_before_enclave
jframe Feb 7, 2020
3ede57d
rename generateEeaPrivacyGroupId -> calculateEeaPrivacyGroupId
jframe Feb 7, 2020
10534ee
Merge branch 'master' into validate_private_tx_before_enclave
jframe Feb 10, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,43 +16,43 @@

import static org.apache.logging.log4j.LogManager.getLogger;
import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcEnclaveErrorConverter.convertEnclaveInvalidReason;
import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcErrorConverter.convertTransactionInvalidReason;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.DECODE_ERROR;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.ENCLAVE_ERROR;

import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcErrorConverter;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacySendTransaction;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacySendTransaction.ErrorResponseException;
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.Transaction;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.TransactionValidator.TransactionInvalidReason;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
import org.hyperledger.besu.ethereum.privacy.MultiTenancyValidationException;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction;
import org.hyperledger.besu.ethereum.privacy.SendTransactionResponse;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPException;

import org.apache.logging.log4j.Logger;
import org.apache.tuweni.bytes.Bytes;

public class EeaSendRawTransaction implements JsonRpcMethod {

private static final Logger LOG = getLogger();
private final PrivacySendTransaction privacySendTransaction;
private final EnclavePublicKeyProvider enclavePublicKeyProvider;
private final TransactionPool transactionPool;
private final PrivacyController privacyController;
private final EnclavePublicKeyProvider enclavePublicKeyProvider;

public EeaSendRawTransaction(
final TransactionPool transactionPool,
final PrivacyController privacyController,
final EnclavePublicKeyProvider enclavePublicKeyProvider) {
this.transactionPool = transactionPool;
this.privacyController = privacyController;
this.privacySendTransaction =
new PrivacySendTransaction(privacyController, enclavePublicKeyProvider);
this.enclavePublicKeyProvider = enclavePublicKeyProvider;
}

Expand All @@ -63,45 +63,40 @@ public String getName() {

@Override
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
final PrivateTransaction privateTransaction;
try {
privateTransaction = privacySendTransaction.validateAndDecodeRequest(requestContext);
} catch (final ErrorResponseException e) {
return e.getResponse();
}
final String rawPrivateTransaction = requestContext.getRequiredParameter(0, String.class);
final Object id = requestContext.getRequest().getId();

final SendTransactionResponse sendTransactionResponse;
try {
sendTransactionResponse =
privacyController.sendTransaction(
privateTransaction, enclavePublicKeyProvider.getEnclaveKey(requestContext.getUser()));
final PrivateTransaction privateTransaction =
PrivateTransaction.readFrom(RLP.input(Bytes.fromHexString(rawPrivateTransaction)));

final String enclavePublicKey =
enclavePublicKeyProvider.getEnclaveKey(requestContext.getUser());
final ValidationResult<TransactionInvalidReason> validationResult =
privacyController.validatePrivateTransaction(privateTransaction, enclavePublicKey);
if (!validationResult.isValid()) {
return new JsonRpcErrorResponse(
id, convertTransactionInvalidReason(validationResult.getInvalidReason()));
}

final String enclaveKey =
privacyController.sendTransaction(privateTransaction, enclavePublicKey);
final Transaction privacyMarkerTransaction =
privacyController.createPrivacyMarkerTransaction(enclaveKey, privateTransaction);

return transactionPool
.addLocalTransaction(privacyMarkerTransaction)
.either(
() -> new JsonRpcSuccessResponse(id, privacyMarkerTransaction.getHash().toString()),
errorReason ->
new JsonRpcErrorResponse(id, convertTransactionInvalidReason(errorReason)));
} catch (final MultiTenancyValidationException e) {
LOG.error("Unauthorized privacy multi-tenancy rpc request. {}", e.getMessage());
return new JsonRpcErrorResponse(requestContext.getRequest().getId(), ENCLAVE_ERROR);
return new JsonRpcErrorResponse(id, ENCLAVE_ERROR);
} catch (final IllegalArgumentException | RLPException e) {
return new JsonRpcErrorResponse(id, DECODE_ERROR);
} catch (final Exception e) {
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), convertEnclaveInvalidReason(e.getMessage()));
return new JsonRpcErrorResponse(id, convertEnclaveInvalidReason(e.getMessage()));
}

return privacySendTransaction.validateAndExecute(
requestContext,
privateTransaction,
sendTransactionResponse.getPrivacyGroupId(),
() -> {
final Transaction privacyMarkerTransaction =
privacyController.createPrivacyMarkerTransaction(
sendTransactionResponse.getEnclaveKey(), privateTransaction);
return transactionPool
.addLocalTransaction(privacyMarkerTransaction)
.either(
() ->
new JsonRpcSuccessResponse(
requestContext.getRequest().getId(),
privacyMarkerTransaction.getHash().toString()),
errorReason ->
new JsonRpcErrorResponse(
requestContext.getRequest().getId(),
JsonRpcErrorConverter.convertTransactionInvalidReason(errorReason)));
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,25 @@
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv;

import static org.apache.logging.log4j.LogManager.getLogger;
import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcEnclaveErrorConverter.convertEnclaveInvalidReason;
import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcErrorConverter.convertTransactionInvalidReason;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.DECODE_ERROR;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.ENCLAVE_ERROR;

import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcEnclaveErrorConverter;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacySendTransaction;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.PrivacySendTransaction.ErrorResponseException;
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.mainnet.TransactionValidator.TransactionInvalidReason;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
import org.hyperledger.besu.ethereum.privacy.MultiTenancyValidationException;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction;
import org.hyperledger.besu.ethereum.privacy.SendTransactionResponse;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPException;

import java.util.Base64;

Expand All @@ -41,15 +44,12 @@ public class PrivDistributeRawTransaction implements JsonRpcMethod {

private static final Logger LOG = getLogger();
private final PrivacyController privacyController;
private final PrivacySendTransaction privacySendTransaction;
private final EnclavePublicKeyProvider enclavePublicKeyProvider;

public PrivDistributeRawTransaction(
final PrivacyController privacyController,
final EnclavePublicKeyProvider enclavePublicKeyProvider) {
this.privacyController = privacyController;
this.privacySendTransaction =
new PrivacySendTransaction(privacyController, enclavePublicKeyProvider);
this.enclavePublicKeyProvider = enclavePublicKeyProvider;
}

Expand All @@ -60,35 +60,36 @@ public String getName() {

@Override
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
final PrivateTransaction privateTransaction;
try {
privateTransaction = privacySendTransaction.validateAndDecodeRequest(requestContext);
} catch (ErrorResponseException e) {
return e.getResponse();
}
final String rawPrivateTransaction = requestContext.getRequiredParameter(0, String.class);
final Object id = requestContext.getRequest().getId();

final SendTransactionResponse sendTransactionResponse;
try {
sendTransactionResponse =
privacyController.sendTransaction(
privateTransaction, enclavePublicKeyProvider.getEnclaveKey(requestContext.getUser()));
final PrivateTransaction privateTransaction =
PrivateTransaction.readFrom(RLP.input(Bytes.fromHexString(rawPrivateTransaction)));

final String enclavePublicKey =
enclavePublicKeyProvider.getEnclaveKey(requestContext.getUser());
final ValidationResult<TransactionInvalidReason> validationResult =
jframe marked this conversation as resolved.
Show resolved Hide resolved
privacyController.validatePrivateTransaction(privateTransaction, enclavePublicKey);
if (!validationResult.isValid()) {
return new JsonRpcErrorResponse(
id, convertTransactionInvalidReason(validationResult.getInvalidReason()));
}

final String enclaveKey =
privacyController.sendTransaction(privateTransaction, enclavePublicKey);
return new JsonRpcSuccessResponse(id, hexEncodeEnclaveKey(enclaveKey));
} catch (final MultiTenancyValidationException e) {
LOG.error("Unauthorized privacy multi-tenancy rpc request. {}", e.getMessage());
return new JsonRpcErrorResponse(requestContext.getRequest().getId(), ENCLAVE_ERROR);
return new JsonRpcErrorResponse(id, ENCLAVE_ERROR);
} catch (final IllegalArgumentException | RLPException e) {
return new JsonRpcErrorResponse(id, DECODE_ERROR);
} catch (final Exception e) {
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(),
JsonRpcEnclaveErrorConverter.convertEnclaveInvalidReason(e.getMessage()));
return new JsonRpcErrorResponse(id, convertEnclaveInvalidReason(e.getMessage()));
}
}

return privacySendTransaction.validateAndExecute(
requestContext,
privateTransaction,
sendTransactionResponse.getPrivacyGroupId(),
() ->
new JsonRpcSuccessResponse(
requestContext.getRequest().getId(),
Bytes.wrap(Base64.getDecoder().decode(sendTransactionResponse.getEnclaveKey()))
.toHexString()));
private String hexEncodeEnclaveKey(final String enclaveKey) {
jframe marked this conversation as resolved.
Show resolved Hide resolved
return Bytes.wrap(Base64.getDecoder().decode(enclaveKey)).toHexString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.google.common.base.MoreObjects;

@JsonPropertyOrder({"jsonrpc", "id", "error"})
public class JsonRpcErrorResponse implements JsonRpcResponse {
Expand Down Expand Up @@ -63,4 +64,9 @@ public boolean equals(final Object o) {
public int hashCode() {
return Objects.hash(id, error);
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("id", id).add("error", error).toString();
}
}
Loading