class PrivDistributeRawTransaction implements JsonRpcMethod {

  @Override
  public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
    final Object id = requestContext.getRequest().getId();
    final String rawPrivateTransaction = requestContext.getRequiredParameter(0, String.class);

    try {
      final PrivateTransaction privateTransaction =
          PrivateTransaction.readFrom(RLP.input(Bytes.fromHexString(rawPrivateTransaction)));

      final String enclavePublicKey =
          enclavePublicKeyProvider.getEnclaveKey(requestContext.getUser());

      if (!privateTransaction.getPrivateFrom().equals(Bytes.fromBase64String(enclavePublicKey))) {
        return new JsonRpcErrorResponse(id, PRIVATE_FROM_DOES_NOT_MATCH_ENCLAVE_PUBLIC_KEY);
      }

      Optional<PrivacyGroup> maybePrivacyGroup = null;
      final Optional<Bytes> maybePrivacyGroupId = privateTransaction.getPrivacyGroupId();
      if (onchainPrivacyGroupsEnabled) {
        if (!maybePrivacyGroupId.isPresent()) {
          return new JsonRpcErrorResponse(id, JsonRpcError.ONCHAIN_PRIVACY_GROUP_ID_NOT_AVAILABLE);
        }
        maybePrivacyGroup =
            privacyController.retrieveOnChainPrivacyGroupWithToBeAddedMembers(
                maybePrivacyGroupId.get(), enclavePublicKey, privateTransaction);
        if (maybePrivacyGroup.isEmpty()) {
          return new JsonRpcErrorResponse(id, JsonRpcError.ONCHAIN_PRIVACY_GROUP_DOES_NOT_EXIST);
        }
      } else { // !onchainPrivacyGroupEnabled
        if (maybePrivacyGroupId.isPresent()) {
          maybePrivacyGroup =
              privacyController.retrieveOffChainPrivacyGroup(
                  maybePrivacyGroupId.get().toBase64String(), enclavePublicKey);
        } else {
          maybePrivacyGroup = Optional.empty();
        }
      }

      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, maybePrivacyGroup);
      return new JsonRpcSuccessResponse(id, hexEncodeEnclaveKey(enclaveKey));
    } catch (final MultiTenancyValidationException e) {
      LOG.error("Unauthorized privacy multi-tenancy rpc request. {}", e.getMessage());
      return new JsonRpcErrorResponse(id, ENCLAVE_ERROR);
    } catch (final IllegalArgumentException | RLPException e) {
      return new JsonRpcErrorResponse(id, DECODE_ERROR);
    } catch (final Exception e) {
      return new JsonRpcErrorResponse(id, convertEnclaveInvalidReason(e.getMessage()));
    }
  }

  public  PrivDistributeRawTransaction(
      final PrivacyController privacyController,
      final EnclavePublicKeyProvider enclavePublicKeyProvider,
      final boolean onchainPrivacyGroupsEnabled);

}