5 min read - Posted 05 Dec 18

Quorum how-to

The original article may be consulted at

Setting up your own Quorum network

Set up the Quorum node network

Generate Enode and nodekey

Each node in the network is identified by a unique id assigned to it called the enode. This enode is the public key corresponding to a private nodekey.

Generate public enode from the private nodekey:

nodekey=`docker run -v <PATH TO DATA FOLDER>:/var/qdata/ consensys/quorum:latest sh -c "/opt/bootnode -genkey /var/qdata/dd/nodekey -writeaddress;cat /var/qdata/dd/nodekey"`;
enode=`docker run -v <PATH TO DATA FOLDER>:/var/qdata/ consensys/quorum:latest sh -c "/opt/bootnode -nodekeyhex $nodekey -writeaddress"`;

Only nodes who's enodes are listed in the static-nodes.json file can participate in the consensus mechanism.

Here is an example of how to generate a static-nodes.json file:

ips=("" "" "" "")
mkdir -p $WORKDIR/q1/dd/
echo "[" > $WORKDIR/q1/dd/static-nodes.json;
for ip in ${ips[*]}; do
    mkdir -p $WORKDIR/q${i}/logs;
    mkdir -p $WORKDIR/q${i}/dd/{keystore,geth};
    enode=`docker run -v $WORKDIR/q${i}:/var/qdata/ consensys/quorum:latest sh -c "/opt/bootnode -genkey /var/qdata/dd/nodekey -writeaddress; cat /var/qdata/dd/nodekey"`;
    enode=`docker run -v $WORKDIR/q${i}:/var/qdata/ consensys/quorum:latest sh -c "/opt/bootnode -nodekeyhex $enode -writeaddress"`;
    sep=`[[ $i < ${#ips[@]} ]] && echo ","`;
    echo '  "enode://'$enode'@'$ip':21000?discport=0"'$sep >> $WORKDIR/q${i}/dd/static-nodes.json;
    let i++;
echo "]" >> $WORKDIR/q1/dd/static-nodes.json

The output should look something like this:

$ cat $WORKDIR/q1/dd/static-nodes.json
Create an initial account

Run: /opt/geth --datadir=$WORKDIR/dd account new

You will be prompted for a password.

Keep a copy of the address returned by the program. You can also see the private key has been stored as a file under $WORKDIR/dd/keystore.

Create a genesis file

All nodes should have in common the first block (the genesis block) and a set of common parameters to operate the network.

An example of genesis JSON file is in this repository under tests/crux_quorum/istanbul-genesis.json.

Please edit the genesis file and add your account to it with a non-zero balance, so you have some Ether when you start the chain.

The JSON file is ingested by the geth init command to initialize the first block.

docker run -it -v <PATH TO DATA FOLDER>:/var/qdata/ -v <PATH TO JSON FILE>:/tmp/genesis.json \ consensys/quorum:latest /opt/geth --datadir /var/qdata/dd init /tmp/genesis.json

Create a list of static and permissioned nodes

As you create the Quorum network, you will need to organize your nodes so they can connect to each other.

You can use two separate files to organize the network:

static-nodes.json: this file contains the list of nodes this Quorum instance will connect to.

permissioned-nodes.json: nodes listed in this file are explicitly allowed to send data to the Quorum instance.

Both files have the same format. Here is an example.

["enode://abcde....1234@, "enode://abcdde...6543@]

Each enode URI is built with the public key of the node, associated with its host name and RPC port. The discport parameter is set to zero as no discovery is performed on the network.

Quorum. data folder structure

Create the folders as follows:

mkdir -p dd/keystore logs

Copy the files created earlier so it conforms to the structure below:

├── dd
│   ├── keystore
│   │   └── key
│   ├── permissioned-nodes.json
│   └── static-nodes.json
├── logs
│   └── node.log
├── nodekey
└── passwords.txt

Set up Tessera or Crux nodes

Generate Constellation keys

For each Constellation instance, you will need a unique keypair.

This command generates a keypair under /tmp/out.key and /tmp/

docker run -v /tmp:/tmp -it consensys/crux:latest /opt/crux --generate-keys /tmp/out

Constellation data folder structure

Create the logs folder: mkdir -p logs

Copy the files created earlier so it conforms to the structure below. Make sure to rename the keypair to tm.key and respectively.

├── logs
│   └── crux.log
├── tm.key

Running the Quorum network

Running Docker

On each node participating in the network, you will need to run Quorum and Constellation (either Crux or Tessera).

Assuming you followed the instructions above, you should have a data folder for Quorum and Constellation respectively.

You can then start Crux with:

env HOSTNAME=<hostname of the crux node> OTHER_NODES=http://<hostname of an other crux node to discover> docker run -p 9000:9000 -v <path to constellation data>:/var/cdata/ <path to quorum data>:/var/qdata/ -it consensys/crux:latest

You can start Quorum with:

docker run -p 22000:22000 -p 21000:21000 -v <path to quorum data>:/var/qdata/ consensys/quorum:latest

You can also use a docker compose yaml configuration file to run both containers together:

version: "3.4"
    image: consensys/crux:latest
    container_name: crux
      - 9000:9000
    restart: always
      - HOSTNAME=<hostname of the crux node>
      - OTHER_NODES=<hostname of an other crux node to discover>
      - ${WORKDIR}/c1:/var/cdata/
      - ${WORKDIR}/q1:/var/qdata/
    image: consensys/quorum:latest
    container_name: quorum
      - 22000:22000
      - 21000:21000
    restart: always
      - ${WORKDIR}/q1:/var/qdata/

Check the network is up and running.

On the node, perform the following to check Constellation is up and running:

curl -vv http://localhost:19001/upcheck

Check the quorum logs to check the node came up without issues.

less <path to quorum data>/logs/node.log

Private Transactions

Example of how to send a private transaction:

Send Private Transaction ``` $ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{"from": "0xed9d02e382b34818e88b88a309c7fe71e65f419d", "to": "0xca843569e3427144cead5e4d5999a3d0ccf92b8e", "gas": "0x76c0", "data": "0xca843569e3427144cead5e4d5999a3d0ccf92b8eed9d02e382b34818e88b88a309c7fe71e65f419d", "privateFor": ["QfeDAys9MPDs2XHExtc84jKGHxZg/aj52DTh0vtA3Xc="]}],"id":1}'

{"jsonrpc":"2.0","id":1,"result":"0xdcbe81138963dc32993ec0a83f6d974e1e3c0ec27fc88f09bfe8c7b54ab51de1"} `` Copy0xdcbe81138963dc32993ec0a83f6d974e1e3c0ec27fc88f09bfe8c7b54ab51de1` from the result field for the next step

Get Transaction Input $ curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionByHash","params":["0xdcbe81138963dc32993ec0a83f6d974e1e3c0ec27fc88f09bfe8c7b54ab51de1"],"id":1}' {"jsonrpc":"2.0","id":1,"result":{"blockHash":"0xe98fc1b2110f60407e9bfefddadf16e5b210b9e12dd0e78b4fe277552078c353","blockNumber":"0x58","from":"0xed9d02e382b34818e88b88a309c7fe71e65f419d","gas":"0x76c0","gasPrice":"0x0","hash":"0xdcbe81138963dc32993ec0a83f6d974e1e3c0ec27fc88f09bfe8c7b54ab51de1","input":"0x7e5b0b4effedf9a3d8c393e2e669a73296066032a0c779d28d5b35234be5da2d529a096efadc8944cc4dfd9bae4ed1efe75c7f7b431584a35dc38c942177884e","nonce":"0x0","to":"0xca843569e3427144cead5e4d5999a3d0ccf92b8e","transactionIndex":"0x0","value":"0x0","v":"0x25","r":"0x174ba76866bea2d7520e004e3f9b573ca058e219347880fc86ab70b4a708a4dc","s":"0x30eba5e128884ce1f5a659b8e978d62d9d438173d2f3cc11c0020f7cdd6a48a5"}}

Copy 0x7e5b0b4effedf9a3d8c393e2e669a73296066032a0c779d28d5b35234be5da2d529a096efadc8944cc4dfd9bae4ed1efe75c7f7b431584a35dc38c942177884e from the input field for the next step

Get Payload from Sending node ``` $ curl -X POST --data '{"jsonrpc":"2.0", "method":"eth_getQuorumPayload", "params":["0x7e5b0b4effedf9a3d8c393e2e669a73296066032a0c779d28d5b35234be5da2d529a096efadc8944cc4dfd9bae4ed1efe75c7f7b431584a35dc38c942177884e"], "id":2}'

{"jsonrpc":"2.0","id":2,"result":"0xca843569e3427144cead5e4d5999a3d0ccf92b8eed9d02e382b34818e88b88a309c7fe71e65f419d"} ```

Get Payload from Receiving node ``` $ curl -X POST --data '{"jsonrpc":"2.0", "method":"eth_getQuorumPayload", "params":["0x7e5b0b4effedf9a3d8c393e2e669a73296066032a0c779d28d5b35234be5da2d529a096efadc8944cc4dfd9bae4ed1efe75c7f7b431584a35dc38c942177884e"], "id":2}'

{"jsonrpc":"2.0","id":2,"result":"0xca843569e3427144cead5e4d5999a3d0ccf92b8eed9d02e382b34818e88b88a309c7fe71e65f419d"} ``` For all other nodes, 0x should be the result: > 0x means that the privateFor public key doesn't match any nodes in the network


Open a shell to a container:

docker exec -it <container_name> /bin/bash

Node Info curl -X POST --data '{"jsonrpc":"2.0","method":"admin_nodeInfo","id":1}'

Get list of connected peers curl -X POST --data '{"jsonrpc":"2.0","method":"admin_peers","id":1}'

Get blocknumber curl -X POST --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'

Created with Sketch.Content is"CC-BY-SA 4.0" licensed
Article On-chain
Article Author

Antoine Toulme





Related Articles
Using Besu, the Java Ethereum Client with Linux/MacOS

Toolbelt: Besu included! Original photo by Jesse Orrico Update: Pantheon is now Hyperledger Besu. For more information, see here. This is the Linux/MacOS version of an article on installing Besu, the Java client for Ethereum: Linux Windows Having some powerful tools in your toolbelt is essential for a Java developer, and one of the crucial tools for an Ethereum blockchain developer is the network client. This is the piece of software that communicates data to and from the blockchain. Among other

Introduction to Pantheon — The Java Ethereum Client

Pantheon is the new Java Ethereum client which has recently been open sourced and is now production ready (v1.1 at the time of writing). The code was written in Java and aims to provide enterprises with an Ethereum client that has features such as stability, permissions and access control, privacy, ease of deployment and scalability. These are common requirements for business looking to use Ethereum in their technology stack. Pantheon is also mainnet-compatible, and includes features like consen