You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by bi...@apache.org on 2018/08/14 20:04:06 UTC

[camel] branch master updated: Added jpmorganchase/quorum

This is an automated email from the ASF dual-hosted git repository.

bibryam pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/master by this push:
     new cfa2bfe  Added jpmorganchase/quorum
cfa2bfe is described below

commit cfa2bfe7f11864260f4dd7ed8935b3f4dd850e46
Author: Bilgin Ibryam <bi...@gmail.com>
AuthorDate: Tue Aug 14 21:02:33 2018 +0100

    Added jpmorganchase/quorum
---
 components/camel-web3j/pom.xml                     |   6 +-
 .../camel-web3j/src/main/docs/web3j-component.adoc |   4 +-
 .../camel/component/web3j/Web3jConfiguration.java  |  28 +++
 .../camel/component/web3j/Web3jConstants.java      |  12 ++
 .../camel/component/web3j/Web3jEndpoint.java       |   5 +
 .../camel/component/web3j/Web3jProducer.java       | 195 ++++++++++++++++++-
 .../camel/component/web3j/Web3jProducerTest.java   |   2 +-
 .../component/web3j/Web3jQuorumProducerTest.java   | 211 +++++++++++++++++++++
 .../integration/Web3jProducerGanacheTest.java      |   4 +
 parent/pom.xml                                     |   1 +
 .../springboot/Web3jComponentConfiguration.java    |  24 +++
 11 files changed, 486 insertions(+), 6 deletions(-)

diff --git a/components/camel-web3j/pom.xml b/components/camel-web3j/pom.xml
index babfede..2f5439e 100644
--- a/components/camel-web3j/pom.xml
+++ b/components/camel-web3j/pom.xml
@@ -56,7 +56,11 @@
             <artifactId>parity</artifactId>
             <version>${web3j-version}</version>
         </dependency>
-
+        <dependency>
+            <groupId>org.web3j</groupId>
+            <artifactId>quorum</artifactId>
+            <version>${web3j-quorum-version}</version>
+        </dependency>
         <!-- for testing -->
         <dependency>
             <groupId>org.apache.camel</groupId>
diff --git a/components/camel-web3j/src/main/docs/web3j-component.adoc b/components/camel-web3j/src/main/docs/web3j-component.adoc
index 0e3dc09..9be54ac 100644
--- a/components/camel-web3j/src/main/docs/web3j-component.adoc
+++ b/components/camel-web3j/src/main/docs/web3j-component.adoc
@@ -63,7 +63,7 @@ with the following path and query parameters:
 |===
 
 
-==== Query Parameters (36 parameters):
+==== Query Parameters (38 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -74,6 +74,8 @@ with the following path and query parameters:
 | *fromBlock* (common) | The block number, or the string latest for the last mined block or pending, earliest for not yet mined transactions. | latest | DefaultBlockParameter
 | *fullTransactionObjects* (common) | If true it returns the full transaction objects, if false only the hashes of the transactions. | false | boolean
 | *gasLimit* (common) | The maximum gas allowed in this block. |  | BigInteger
+| *privateFor* (common) | A transaction privateFor nodes with public keys in a Quorum network |  | List
+| *quorumAPI* (common) | If true, this will support Quorum API. | false | boolean
 | *toAddress* (common) | The address the transaction is directed to. |  | String
 | *toBlock* (common) | The block number, or the string latest for the last mined block or pending, earliest for not yet mined transactions. | latest | DefaultBlockParameter
 | *topics* (common) | Topics are order-dependent. Each topic can also be a list of topics. Specify multiple topics separated by comma. |  | String
diff --git a/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jConfiguration.java b/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jConfiguration.java
index d06929f..f65fc7c 100644
--- a/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jConfiguration.java
+++ b/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jConfiguration.java
@@ -126,6 +126,34 @@ public class Web3jConfiguration implements Cloneable {
     @UriParam(label = "common")
     private boolean fullTransactionObjects;
 
+    @UriParam(label = "common", defaultValue = "false")
+    private boolean quorumAPI;
+
+    @UriParam(label = "common")
+    private List<String>  privateFor;
+
+
+    public List<String> getPrivateFor() {
+        return privateFor;
+    }
+    /**
+     *  A transaction privateFor nodes with public keys in a Quorum network
+     */
+    public void setPrivateFor(List<String> privateFor) {
+        this.privateFor = privateFor;
+    }
+
+
+    public boolean isQuorumAPI() {
+        return quorumAPI;
+    }
+    /**
+     *  If true, this will support Quorum API.
+     */
+    public void setQuorumAPI(boolean quorumAPI) {
+        this.quorumAPI = quorumAPI;
+    }
+
     public Web3j getWeb3j() {
         return web3j;
     }
diff --git a/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jConstants.java b/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jConstants.java
index 1830372..409afd7 100644
--- a/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jConstants.java
+++ b/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jConstants.java
@@ -80,6 +80,17 @@ public interface Web3jConstants {
     String SHH_GET_FILTER_CHANGES = "SHH_GET_FILTER_CHANGES";
     String SHH_GET_MESSAGES = "SHH_GET_MESSAGES";
 
+    String QUORUM_ETH_SEND_TRANSACTION = "QUORUM_ETH_SEND_TRANSACTION";
+    String QUORUM_NODE_INFO = "QUORUM_NODE_INFO";
+    String QUORUM_CANONICAL_HASH = "QUORUM_CANONICAL_HASH";
+    String QUORUM_VOTE = "QUORUM_VOTE";
+    String QUORUM_MAKE_BLOCK = "QUORUM_MAKE_BLOCK";
+    String QUORUM_PAUSE_BLOCK_MAKER= "QUORUM_PAUSE_BLOCK_MAKER";
+    String QUORUM_RESUME_BLOCK_MAKER= "QUORUM_RESUME_BLOCK_MAKER";
+    String QUORUM_IS_BLOCK_MAKER = "QUORUM_IS_BLOCK_MAKER";
+    String QUORUM_IS_VOTER = "QUORUM_IS_VOTER";
+    String QUORUM_GET_PRIVATE_PAYLOAD = "QUORUM_GET_PRIVATE_PAYLOAD";
+
     String ETH_LOG_OBSERVABLE = "ETH_LOG_OBSERVABLE";
     String ETH_BLOCK_HASH_OBSERVABLE = "ETH_BLOCK_HASH_OBSERVABLE";
     String ETH_PENDING_TRANSACTION_HASH_OBSERVABLE = "ETH_PENDING_TRANSACTION_HASH_OBSERVABLE";
@@ -125,6 +136,7 @@ public interface Web3jConstants {
     String TOPICS = "TOPICS";
     String PRIORITY = "PRIORITY";
     String TTL = "TTL";
+    String PRIVATE_FOR = "PRIVATE_FOR";
 
     String ERROR_CODE = "ERROR_CODE";
     String ERROR_DATA = "ERROR_DATA";
diff --git a/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jEndpoint.java b/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jEndpoint.java
index cf69f64..d533a8f 100644
--- a/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jEndpoint.java
+++ b/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jEndpoint.java
@@ -37,6 +37,7 @@ import org.web3j.protocol.core.methods.request.ShhFilter;
 import org.web3j.protocol.http.HttpService;
 import org.web3j.protocol.ipc.UnixIpcService;
 import org.web3j.protocol.ipc.WindowsIpcService;
+import org.web3j.quorum.Quorum;
 
 /**
  * The web3j component uses the Web3j client API and allows you to add/read nodes to/from a web3j compliant content repositories.
@@ -99,6 +100,10 @@ public class Web3jEndpoint extends DefaultEndpoint {
             web3jService = new UnixIpcService(clientAddress);
         }
 
+        if (configuration.isQuorumAPI()) {
+            return Quorum.build(web3jService);
+        }
+
         return Web3j.build(web3jService);
     }
 
diff --git a/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jProducer.java b/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jProducer.java
index b784eed..4c52e57 100644
--- a/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jProducer.java
+++ b/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jProducer.java
@@ -80,8 +80,18 @@ import org.web3j.protocol.core.methods.response.ShhNewIdentity;
 import org.web3j.protocol.core.methods.response.ShhPost;
 import org.web3j.protocol.core.methods.response.ShhUninstallFilter;
 import org.web3j.protocol.core.methods.response.ShhVersion;
+import org.web3j.protocol.core.methods.response.VoidResponse;
 import org.web3j.protocol.core.methods.response.Web3ClientVersion;
 import org.web3j.protocol.core.methods.response.Web3Sha3;
+import org.web3j.quorum.Quorum;
+import org.web3j.quorum.methods.request.PrivateTransaction;
+import org.web3j.quorum.methods.response.BlockMaker;
+import org.web3j.quorum.methods.response.CanonicalHash;
+import org.web3j.quorum.methods.response.MakeBlock;
+import org.web3j.quorum.methods.response.PrivatePayload;
+import org.web3j.quorum.methods.response.QuorumNodeInfo;
+import org.web3j.quorum.methods.response.Vote;
+import org.web3j.quorum.methods.response.Voter;
 
 /**
  * The web3j producer.
@@ -90,14 +100,16 @@ import org.web3j.protocol.core.methods.response.Web3Sha3;
 public class Web3jProducer extends HeaderSelectorProducer {
     private static final Logger LOG = LoggerFactory.getLogger(Web3jProducer.class);
     private Web3j web3j;
+    private Quorum quorum;
     private Web3jConfiguration configuration;
-    private Web3jEndpoint endpoint;
 
     public Web3jProducer(Web3jEndpoint endpoint, final Web3jConfiguration configuration) {
         super(endpoint, Web3jConstants.OPERATION, () -> configuration.getOperationOrDefault(), false);
         web3j = endpoint.getWeb3j();
-        this.endpoint = endpoint;
         this.configuration = configuration;
+        if (web3j instanceof Quorum) {
+            quorum = (Quorum) web3j;
+        }
     }
 
     @Override
@@ -909,6 +921,180 @@ public class Web3jProducer extends HeaderSelectorProducer {
         }
     }
 
+    // Quorum API Operations
+    @InvokeOnHeader(Web3jConstants.QUORUM_NODE_INFO)
+    void quorumNodeInfo(Message message) throws IOException {
+        if (quorum == null) {
+            setQuorumEndpointError(message);
+            return;
+        }
+
+        Request<?, QuorumNodeInfo> request = quorum.quorumNodeInfo();
+        setRequestId(message, request);
+        QuorumNodeInfo response = request.send();
+        boolean hasError = checkForError(message, response);
+        if (!hasError) {
+            message.setBody(response.getNodeInfo());
+        }
+    }
+
+    @InvokeOnHeader(Web3jConstants.QUORUM_CANONICAL_HASH)
+    void quorumCanonicalHash(Message message) throws IOException {
+        if (quorum == null) {
+            setQuorumEndpointError(message);
+            return;
+        }
+
+        Request<?, CanonicalHash> request = quorum.quorumCanonicalHash(message.getBody(BigInteger.class));
+        setRequestId(message, request);
+        CanonicalHash response = request.send();
+        boolean hasError = checkForError(message, response);
+        if (!hasError) {
+            message.setBody(response.getCanonicalHash());
+        }
+    }
+
+    @InvokeOnHeader(Web3jConstants.QUORUM_VOTE)
+    void quorumVote(Message message) throws IOException {
+        if (quorum == null) {
+            setQuorumEndpointError(message);
+            return;
+        }
+
+        String blockHash = message.getHeader(Web3jConstants.BLOCK_HASH, configuration::getBlockHash, String.class);
+        Request<?, Vote> request = quorum.quorumVote(blockHash);
+        setRequestId(message, request);
+        Vote response = request.send();
+        boolean hasError = checkForError(message, response);
+        if (!hasError) {
+            message.setBody(response.getTransactionHash());
+        }
+    }
+
+    @InvokeOnHeader(Web3jConstants.QUORUM_MAKE_BLOCK)
+    void quorumMakeBlock(Message message) throws IOException {
+        if (quorum == null) {
+            setQuorumEndpointError(message);
+            return;
+        }
+
+        Request<?, MakeBlock> request = quorum.quorumMakeBlock();
+        setRequestId(message, request);
+        MakeBlock response = request.send();
+        boolean hasError = checkForError(message, response);
+        if (!hasError) {
+            message.setBody(response.getBlockHash());
+        }
+    }
+
+    @InvokeOnHeader(Web3jConstants.QUORUM_PAUSE_BLOCK_MAKER)
+    void quorumPauseBlockMaker(Message message) throws IOException {
+        if (quorum == null) {
+            setQuorumEndpointError(message);
+            return;
+        }
+
+        Request<?, VoidResponse> request = quorum.quorumPauseBlockMaker();
+        setRequestId(message, request);
+        VoidResponse response = request.send();
+        boolean hasError = checkForError(message, response);
+        if (!hasError) {
+            message.setBody(response.isValid());
+        }
+    }
+
+    @InvokeOnHeader(Web3jConstants.QUORUM_RESUME_BLOCK_MAKER)
+    void quorumResumeBlockMaker(Message message) throws IOException {
+        if (quorum == null) {
+            setQuorumEndpointError(message);
+            return;
+        }
+
+        Request<?, VoidResponse> request = quorum.quorumResumeBlockMaker();
+        setRequestId(message, request);
+        VoidResponse response = request.send();
+        boolean hasError = checkForError(message, response);
+        if (!hasError) {
+            message.setBody(response.isValid());
+        }
+    }
+
+    @InvokeOnHeader(Web3jConstants.QUORUM_IS_BLOCK_MAKER)
+    void quorumIsBlockMaker(Message message) throws IOException {
+        if (quorum == null) {
+            setQuorumEndpointError(message);
+            return;
+        }
+
+        String address = message.getHeader(Web3jConstants.ADDRESS, configuration::getAddress, String.class);
+        Request<?, BlockMaker> request = quorum.quorumIsBlockMaker(address);
+        setRequestId(message, request);
+        BlockMaker response = request.send();
+        boolean hasError = checkForError(message, response);
+        if (!hasError) {
+            message.setBody(response.isBlockMaker());
+        }
+    }
+
+    @InvokeOnHeader(Web3jConstants.QUORUM_IS_VOTER)
+    void quorumIsVoter(Message message) throws IOException {
+        if (quorum == null) {
+            setQuorumEndpointError(message);
+            return;
+        }
+
+        String address = message.getHeader(Web3jConstants.ADDRESS, configuration::getAddress, String.class);
+        Request<?, Voter> request = quorum.quorumIsVoter(address);
+        setRequestId(message, request);
+        Voter response = request.send();
+        boolean hasError = checkForError(message, response);
+        if (!hasError) {
+            message.setBody(response.isVoter());
+        }
+    }
+
+    @InvokeOnHeader(Web3jConstants.QUORUM_GET_PRIVATE_PAYLOAD)
+    void quorumGetPrivatePayload(Message message) throws IOException {
+        if (quorum == null) {
+            setQuorumEndpointError(message);
+            return;
+        }
+
+        Request<?, PrivatePayload> request = quorum.quorumGetPrivatePayload(message.getBody(String.class));
+        setRequestId(message, request);
+        PrivatePayload response = request.send();
+        boolean hasError = checkForError(message, response);
+        if (!hasError) {
+            message.setBody(response.getPrivatePayload());
+        }
+    }
+
+    @InvokeOnHeader(Web3jConstants.QUORUM_ETH_SEND_TRANSACTION)
+    void quorumEthSendTransaction(Message message) throws IOException {
+        if (quorum == null) {
+            setQuorumEndpointError(message);
+            return;
+        }
+
+        //the same as a regular transaction, but there is no gasPrice, instead there is optional privateFor
+        String fromAddress = message.getHeader(Web3jConstants.FROM_ADDRESS, configuration::getFromAddress, String.class);
+        String toAddress = message.getHeader(Web3jConstants.TO_ADDRESS, configuration::getToAddress, String.class);
+        BigInteger nonce = message.getHeader(Web3jConstants.NONCE, configuration::getNonce, BigInteger.class);
+        BigInteger gasLimit = message.getHeader(Web3jConstants.GAS_LIMIT, configuration::getGasLimit, BigInteger.class);
+        BigInteger value = message.getHeader(Web3jConstants.VALUE, configuration::getValue, BigInteger.class);
+        String data = message.getHeader(Web3jConstants.DATA, configuration::getData, String.class);
+        List<String> privateFor = message.getHeader(Web3jConstants.PRIVATE_FOR, configuration::getPrivateFor, List.class);
+        PrivateTransaction transaction = new PrivateTransaction(fromAddress, nonce, gasLimit, toAddress, value, data, privateFor);
+
+        Request<?, EthSendTransaction> request = quorum.ethSendTransaction(transaction);
+        setRequestId(message, request);
+        EthSendTransaction response = request.send();
+        boolean hasError = checkForError(message, response);
+        if (!hasError) {
+            message.setBody(response.getTransactionHash());
+        }
+    }
+
     private void setRequestId(Message message, Request request) {
         final Long id = message.getHeader(Web3jConstants.ID, Long.class);
         LOG.debug("setRequestId " + id);
@@ -934,7 +1120,6 @@ public class Web3jProducer extends HeaderSelectorProducer {
         return defaultBlockParameter;
     }
 
-
     private boolean checkForError(Message message, Response response) {
         if (response.hasError()) {
             int code = response.getError().getCode();
@@ -949,4 +1134,8 @@ public class Web3jProducer extends HeaderSelectorProducer {
             return false;
         }
     }
+
+    private void setQuorumEndpointError(Message message) {
+        message.getExchange().setException(new CamelExchangeException("This is not a Quorum endpoint. Create one by specifying quorumAPI=true", message.getExchange()));
+    }
 }
diff --git a/components/camel-web3j/src/test/java/org/apache/camel/component/web3j/Web3jProducerTest.java b/components/camel-web3j/src/test/java/org/apache/camel/component/web3j/Web3jProducerTest.java
index e86fe66..72ed9dd 100644
--- a/components/camel-web3j/src/test/java/org/apache/camel/component/web3j/Web3jProducerTest.java
+++ b/components/camel-web3j/src/test/java/org/apache/camel/component/web3j/Web3jProducerTest.java
@@ -158,7 +158,7 @@ public class Web3jProducerTest extends Web3jMockTestSupport {
 
     @Test
     public void netPeerCountTest() throws Exception {
-        BigInteger peerCount = BigInteger.valueOf(1L);
+        BigInteger peerCount = BigInteger.ONE;
         NetPeerCount response = Mockito.mock(NetPeerCount.class);
         Mockito.when(mockWeb3j.netPeerCount()).thenReturn(request);
         Mockito.when(request.send()).thenReturn(response);
diff --git a/components/camel-web3j/src/test/java/org/apache/camel/component/web3j/Web3jQuorumProducerTest.java b/components/camel-web3j/src/test/java/org/apache/camel/component/web3j/Web3jQuorumProducerTest.java
new file mode 100644
index 0000000..ad0cde2
--- /dev/null
+++ b/components/camel-web3j/src/test/java/org/apache/camel/component/web3j/Web3jQuorumProducerTest.java
@@ -0,0 +1,211 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.component.web3j;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Produce;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.JndiRegistry;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.web3j.protocol.core.Request;
+import org.web3j.protocol.core.methods.response.EthSendTransaction;
+import org.web3j.protocol.core.methods.response.VoidResponse;
+import org.web3j.quorum.Quorum;
+import org.web3j.quorum.methods.response.BlockMaker;
+import org.web3j.quorum.methods.response.CanonicalHash;
+import org.web3j.quorum.methods.response.MakeBlock;
+import org.web3j.quorum.methods.response.PrivatePayload;
+import org.web3j.quorum.methods.response.QuorumNodeInfo;
+import org.web3j.quorum.methods.response.Vote;
+import org.web3j.quorum.methods.response.Voter;
+
+import static org.apache.camel.component.web3j.Web3jConstants.OPERATION;
+import static org.mockito.ArgumentMatchers.any;
+
+public class Web3jQuorumProducerTest extends Web3jMockTestSupport {
+
+    @Mock
+    protected Quorum mockQuorum;
+
+    @Override
+    protected JndiRegistry createRegistry() throws Exception {
+        JndiRegistry registry = super.createRegistry();
+        registry.bind("mockQuorum", mockQuorum);
+        return registry;
+    }
+
+    protected String getUrl() {
+        return "web3j://http://127.0.0.1:8545?web3j=#mockQuorum&quorumAPI=true&";
+    }
+
+    @Produce(uri = "direct:start")
+    protected ProducerTemplate template;
+
+    @Mock
+    private Request request;
+
+    @Override
+    public boolean isUseAdviceWith() {
+        return false;
+    }
+
+    //Quorum API tests
+    @Test
+    public void quorumNodeInfoTest() throws Exception {
+        QuorumNodeInfo.NodeInfo nodeInfo = new QuorumNodeInfo.NodeInfo();
+        QuorumNodeInfo response = Mockito.mock(QuorumNodeInfo.class);
+
+        Mockito.when(mockQuorum.quorumNodeInfo()).thenReturn(request);
+        Mockito.when(request.send()).thenReturn(response);
+        Mockito.when(response.getNodeInfo()).thenReturn(nodeInfo);
+
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, Web3jConstants.QUORUM_NODE_INFO);
+        template.send(exchange);
+        QuorumNodeInfo.NodeInfo body = exchange.getIn().getBody(QuorumNodeInfo.NodeInfo.class);
+        assertTrue(body != null);
+    }
+
+    @Test
+    public void quorumCanonicalHashTest() throws Exception {
+        CanonicalHash response = Mockito.mock(CanonicalHash.class);
+        Mockito.when(mockQuorum.quorumCanonicalHash(any())).thenReturn(request);
+        Mockito.when(request.send()).thenReturn(response);
+        Mockito.when(response.getCanonicalHash()).thenReturn("test");
+
+        Exchange exchange = createExchangeWithBodyAndHeader("test-hash", OPERATION, Web3jConstants.QUORUM_CANONICAL_HASH);
+        template.send(exchange);
+        String body = exchange.getIn().getBody(String.class);
+        assertTrue(body.equals("test"));
+    }
+
+    @Test
+    public void quorumVoteTest() throws Exception {
+        Vote response = Mockito.mock(Vote.class);
+        Mockito.when(mockQuorum.quorumVote(any())).thenReturn(request);
+        Mockito.when(request.send()).thenReturn(response);
+        Mockito.when(response.getTransactionHash()).thenReturn("test");
+
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, Web3jConstants.QUORUM_VOTE);
+        template.send(exchange);
+        String body = exchange.getIn().getBody(String.class);
+        assertTrue(body.equals("test"));
+    }
+
+    @Test
+    public void quorumMakeBlockTest() throws Exception {
+        MakeBlock response = Mockito.mock(MakeBlock.class);
+        Mockito.when(mockQuorum.quorumMakeBlock()).thenReturn(request);
+        Mockito.when(request.send()).thenReturn(response);
+        Mockito.when(response.getBlockHash()).thenReturn("test");
+
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, Web3jConstants.QUORUM_MAKE_BLOCK);
+        template.send(exchange);
+        String body = exchange.getIn().getBody(String.class);
+        assertTrue(body.equals("test"));
+    }
+
+    @Test
+    public void quorumPauseBlockMakerTest() throws Exception {
+        VoidResponse response = Mockito.mock(VoidResponse.class);
+        Mockito.when(mockQuorum.quorumPauseBlockMaker()).thenReturn(request);
+        Mockito.when(request.send()).thenReturn(response);
+        Mockito.when(response.isValid()).thenReturn(Boolean.TRUE);
+
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, Web3jConstants.QUORUM_PAUSE_BLOCK_MAKER);
+        template.send(exchange);
+        Boolean body = exchange.getIn().getBody(Boolean.class);
+        assertTrue(body);
+    }
+
+    @Test
+    public void quorumResumeBlockMakerTest() throws Exception {
+        VoidResponse response = Mockito.mock(VoidResponse.class);
+        Mockito.when(mockQuorum.quorumResumeBlockMaker()).thenReturn(request);
+        Mockito.when(request.send()).thenReturn(response);
+        Mockito.when(response.isValid()).thenReturn(Boolean.TRUE);
+
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, Web3jConstants.QUORUM_RESUME_BLOCK_MAKER);
+        template.send(exchange);
+        Boolean body = exchange.getIn().getBody(Boolean.class);
+        assertTrue(body);
+    }
+
+    @Test
+    public void quorumIsBlockMakerTest() throws Exception {
+        BlockMaker response = Mockito.mock(BlockMaker.class);
+        Mockito.when(mockQuorum.quorumIsBlockMaker(any())).thenReturn(request);
+        Mockito.when(request.send()).thenReturn(response);
+        Mockito.when(response.isBlockMaker()).thenReturn(Boolean.TRUE);
+
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, Web3jConstants.QUORUM_IS_BLOCK_MAKER);
+        template.send(exchange);
+        Boolean body = exchange.getIn().getBody(Boolean.class);
+        assertTrue(body);
+    }
+
+    @Test
+    public void quorumIsVoterTest() throws Exception {
+        Voter response = Mockito.mock(Voter.class);
+        Mockito.when(mockQuorum.quorumIsVoter(any())).thenReturn(request);
+        Mockito.when(request.send()).thenReturn(response);
+        Mockito.when(response.isVoter()).thenReturn(Boolean.TRUE);
+
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, Web3jConstants.QUORUM_IS_VOTER);
+        template.send(exchange);
+        Boolean body = exchange.getIn().getBody(Boolean.class);
+        assertTrue(body);
+    }
+
+    @Test
+    public void quorumGetPrivatePayloadTest() throws Exception {
+        PrivatePayload response = Mockito.mock(PrivatePayload.class);
+        Mockito.when(mockQuorum.quorumGetPrivatePayload(any())).thenReturn(request);
+        Mockito.when(request.send()).thenReturn(response);
+        Mockito.when(response.getPrivatePayload()).thenReturn("secret");
+
+        Exchange exchange = createExchangeWithBodyAndHeader("foo", OPERATION, Web3jConstants.QUORUM_GET_PRIVATE_PAYLOAD);
+        template.send(exchange);
+        String body = exchange.getIn().getBody(String.class);
+        assertTrue(body.equals("secret"));
+    }
+
+    @Test
+    public void quorumEthSendTransactionTest() throws Exception {
+        EthSendTransaction response = Mockito.mock(EthSendTransaction.class);
+        Mockito.when(mockQuorum.ethSendTransaction(any())).thenReturn(request);
+        Mockito.when(request.send()).thenReturn(response);
+        Mockito.when(response.getTransactionHash()).thenReturn("test");
+
+        Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION, Web3jConstants.QUORUM_ETH_SEND_TRANSACTION);
+        template.send(exchange);
+        String body = exchange.getIn().getBody(String.class);
+        assertTrue(body.equals("test"));
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                from("direct:start")
+                        .to(getUrl() + OPERATION.toLowerCase() + "=" + Web3jConstants.WEB3_CLIENT_VERSION);
+            }
+        };
+    }
+}
diff --git a/components/camel-web3j/src/test/java/org/apache/camel/component/web3j/integration/Web3jProducerGanacheTest.java b/components/camel-web3j/src/test/java/org/apache/camel/component/web3j/integration/Web3jProducerGanacheTest.java
index ee8146a..1a5e7fa 100644
--- a/components/camel-web3j/src/test/java/org/apache/camel/component/web3j/integration/Web3jProducerGanacheTest.java
+++ b/components/camel-web3j/src/test/java/org/apache/camel/component/web3j/integration/Web3jProducerGanacheTest.java
@@ -24,6 +24,7 @@ import org.apache.camel.Exchange;
 import org.apache.camel.Produce;
 import org.apache.camel.ProducerTemplate;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.web3j.Web3jConstants;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.web3j.protocol.core.methods.response.EthBlock;
@@ -343,6 +344,9 @@ public class Web3jProducerGanacheTest extends Web3jIntegrationTestSupport {
         exchange.getIn().setHeader(GAS_PRICE, BigInteger.valueOf(10000000000000L));
         exchange.getIn().setHeader(GAS_LIMIT, BigInteger.valueOf(30400L));
         exchange.getIn().setHeader(VALUE, BigInteger.valueOf(50000000000000L));
+
+//        String data = message.getHeader(Web3jConstants.DATA, configuration::getData, String.class);
+//
         template.send(exchange);
         String body = exchange.getIn().getBody(String.class);
         assertTrue(body != null);
diff --git a/parent/pom.xml b/parent/pom.xml
index 9297407..23bb7ab 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -703,6 +703,7 @@
     <vertx-version>3.5.3</vertx-version>
     <vysper-version>0.7</vysper-version>
     <web3j-version>3.5.0</web3j-version>
+    <web3j-quorum-version>0.8.0</web3j-quorum-version>
     <weld1-version>1.1.28.Final</weld1-version>
     <weld2-version>2.4.7.Final</weld2-version>
     <weld3-version>3.0.5.Final</weld3-version>
diff --git a/platforms/spring-boot/components-starter/camel-web3j-starter/src/main/java/org/apache/camel/component/web3j/springboot/Web3jComponentConfiguration.java b/platforms/spring-boot/components-starter/camel-web3j-starter/src/main/java/org/apache/camel/component/web3j/springboot/Web3jComponentConfiguration.java
index fc125ad..41d16e4 100644
--- a/platforms/spring-boot/components-starter/camel-web3j-starter/src/main/java/org/apache/camel/component/web3j/springboot/Web3jComponentConfiguration.java
+++ b/platforms/spring-boot/components-starter/camel-web3j-starter/src/main/java/org/apache/camel/component/web3j/springboot/Web3jComponentConfiguration.java
@@ -72,6 +72,14 @@ public class Web3jComponentConfiguration
     public static class Web3jConfigurationNestedConfiguration {
         public static final Class CAMEL_NESTED_CLASS = org.apache.camel.component.web3j.Web3jConfiguration.class;
         /**
+         * A transaction privateFor nodes with public keys in a Quorum network
+         */
+        private List privateFor;
+        /**
+         * If true, this will support Quorum API.
+         */
+        private Boolean quorumAPI = false;
+        /**
          * The preconfigured Web3j object.
          */
         private Web3j web3j;
@@ -195,6 +203,22 @@ public class Web3jComponentConfiguration
          */
         private String operation = "transaction";
 
+        public List getPrivateFor() {
+            return privateFor;
+        }
+
+        public void setPrivateFor(List privateFor) {
+            this.privateFor = privateFor;
+        }
+
+        public Boolean getQuorumAPI() {
+            return quorumAPI;
+        }
+
+        public void setQuorumAPI(Boolean quorumAPI) {
+            this.quorumAPI = quorumAPI;
+        }
+
         public Web3j getWeb3j() {
             return web3j;
         }