quorum-examples will be deprecated on July 11th 2022, from when we will stop supporting the project.
From now on, we encourage all users to use to quorum-dev-quickstart which is a similar tool offering extra compatibility with Quorum products, in particular Hyperledger Besu and Orchestrate.
We will continue to support quorum-examples in particular fixing bugs until the end of July 2022.
If you have any questions or concerns, please reach out to the ConsenSys protocol engineering team on #Discord or by email.
This project is meant for Quorum users (mainly Quorum contributors) who are already familiar with Quorum deployments and who are looking for some configurations for their network.
If you have a limited experience with Quorum, or if you are looking to start a Quorum network for some testing purposes then you should instead use our quorum-dev-quickstart.
We do not guarantee that all scripts in this project work out of the box, in particular some scripts may be out of date and will require some adjustments from users to properly work on latest Quorum versions.
Current examples include:
Additional examples exist highlighting and showcasing the functionality offered by the Quorum platform. An up-to-date list can be found in the Quorum Documentation site.
Clone the quorum-examples
repo.
git clone https://github.com/Consensys/quorum-examples.git
Important note: Any account/encryption keys used in the quorum-examples repo are for demonstration and testing purposes only. Before running a real environment, new keys should be generated using Geth's account
tool, Tessera's -keygen
option, and Constellation's --generate-keys
option
A 7 node Quorum network must be running before the example can be run. The quorum-examples
repo provides the means to create a pre-configured sample network in minutes.
There are 3 ways to start the sample network, each method is detailed below:
docker-compose
against a preconfigured compose
file to create the sample network: Running with DockerYour environment must be prepared differently depending on the method being used to run the example.
Install VirtualBox
Install Vagrant
Download and start the Vagrant instance (note: running vagrant up
takes approx 5 mins):
git clone https://github.com/Consensys/quorum-examples
cd quorum-examples
vagrant up
vagrant ssh
To shutdown the Vagrant instance, run vagrant suspend
. To delete it, run
vagrant destroy
. To start from scratch, run vagrant up
after destroying the
instance.
sudo rm -r /opt/vagrant/embedded/bin/curl
. This is usually due to
issues with the version of curl bundled with Vagrant.default: cp: cannot open '/path/to/geth.ipc' for reading: Operation not supported
after running vagrant up
, run ./raft-init.sh
within the 7nodes directory on your local machine. This will remove temporary files created after running 7nodes locally and will enable vagrant up
to execute correctly. If encountering an error like
VBoxManage: error: Details: code NS_ERROR_FAILURE (0x80004005), component MachineWrap, interface IMachine
during vagrant up
try the following:
The Vagrant instance is allocated 6 GB of memory. This is defined in the Vagrantfile
, v.memory = 6144
. This has been deemed a suitable value to allow the VM and examples to run as expected. The memory allocation can be changed by updating this value and running vagrant reload
to apply the change.
If the machine you are using has less than 8 GB memory you will likely encounter system issues such as slow down and unresponsiveness when starting the Vagrant instance as your machine will not have the capacity to run the VM. There are several steps that can be taken to overcome this:
docker-compose
, follow this to install Docker Composedocker-compose
git clone https://github.com/Consensys/quorum-examples
cd quorum-examples
docker-compose up -d
QUORUM_CONSENSUS=raft
before running docker-compose
. To start a Quorum node without its associated privacy transaction manager, set PRIVATE_CONFIG=ignore
. QUORUM_CONSENSUS
and PRIVATE_CONFIG
can be set together.
PRIVATE_CONFIG=ignore QUORUM_CONSENSUS=raft docker-compose up -d
Note that additional geth command line parameters can also be specified via the environment variable QUORUM_GETH_ARGS
docker ps
to verify that all quorum-examples containers (7 nodes and 7 tx managers) are healthydocker logs <container-name> -f
to view the logs for a particular containerNote: to run the 7nodes demo, use the following snippet to open geth
Javascript console to a desired node (using container name from docker ps
) and send a private transaction
$ docker exec -it quorum-examples_node1_1 geth attach /qdata/dd/geth.ipc
Welcome to the Geth JavaScript console!
instance: Geth/node1-istanbul/v1.7.2-stable/linux-amd64/go1.9.7
coinbase: 0xd8dba507e85f116b1f7e231ca8525fc9008a6966
at block: 70 (Thu, 18 Oct 2018 14:49:47 UTC)
datadir: /qdata/dd
modules: admin:1.0 debug:1.0 eth:1.0 istanbul:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0
> loadScript('/examples/private-contract.js')
docker-compose down
quorum-examples
folder is not shared--privileged
Note: Quorum must be run on Ubuntu-based/macOS machines. Constellation can only be run on Ubuntu-based machines. Running the examples therefore requires an Ubuntu-based/macOS machine. If running the examples using Constellation then an Ubuntu-based machine is required.
Install Golang
Download and build Quorum:
git clone https://github.com/Consensys/quorum
cd quorum
make
GETHDIR=`pwd`; export PATH=$GETHDIR/build/bin:$PATH
cd ..
Download and build Tessera (see README for build options)
git clone https://github.com/Consensys/tessera.git
cd tessera
mvn install
Download quorum-examples
git clone https://github.com/Consensys/quorum-examples
Note: This is not required if docker-compose
has been used to prepare the network as the docker-compose
command performs these actions for you
Shell scripts are included in the examples to make it simple to configure the network and start submitting transactions.
All logs and temporary data are written to the qdata
folder.
The sample network can be created to run using Istanbul BFT, QBFT, Raft or Clique POA consensus mechanisms. In the following commands replace {consensus}
with one of raft
, istanbul
qbft
or clique
depending on the consensus mechanism you want to use.
Navigate to the 7nodes example directory, configure the Quorum nodes and initialize accounts & keystores:
cd path/to/7nodes
./{consensus}-init.sh
Start the Quorum and privacy manager nodes (Constellation or Tessera):
If running in Vagrant:
./{consensus}-start.sh
By default, Tessera will be used as the privacy manager. To use Constellation run the following:
./{consensus}-start.sh constellation
If running locally:
TESSERA_{JAR|SCRIPT}=/path/to/jar-or-startscript ./{consensus}-start.sh
The {consensus}-start.sh
scripts look for a Tessera executable at default paths unique to the Vagrant environment. When running locally these defaults must be overriden with the TESSERA_SCRIPT
or TESSERA_JAR
environment variables. Set TESSERA_SCRIPT
when using the newer versions of Tessera distributed as a .tar
- extract the tar and set TESSERA_SCRIPT
to the contained runnable script. Set TESSERA_JAR
when using older versions of Tessera distributed as an executable .jar
.
You are now ready to start sending private/public transactions between the nodes
To stop the network:
./stop.sh
quorum-examples
includes some simple transaction contracts to demonstrate the privacy features of Quorum. See the 7nodes Example page for details on how to run them.
It is easy to reduce the number of nodes used in the example network. You may want to do this for memory usage reasons or just to experiment with a different network configuration.
For example, to run the example with 5 nodes instead of 7, follow these steps:
Update the list of nodes involved in consensus
permissioned-nodes.json
(i.e. the entries with raftport
50406
and 50407
). Ensure that there is no trailing comma on the last row of enode details in the file.If using IBFT
Find the 20-byte address representations of node 6 and node 7's nodekey (nodekeys located at qdata/dd{i}/geth/nodekey
). There are many ways to do this, one is to run a script making use of ethereumjs-wallet
:
const wlt = require('ethereumjs-wallet');
var nodekey = '1be3b50b31734be48452c29d714941ba165ef0cbf3ccea8ca16c45e3d8d45fb0';
var wallet = wlt.fromPrivateKey(Buffer.from(nodekey, 'hex'));
console.log('addr: ' + wallet.getAddressString());
istanbul-tools
to decode the extraData
field in istanbul-genesis.json
git clone https://github.com/Consensys/istanbul-tools.git
cd istanbul-tools
make istanbul
./build/bin/istanbul extra decode --extradata <...>
.toml
file and update the formatting to the following:
vanity = "0x0000000000000000000000000000000000000000000000000000000000000000"
validators = [
"0xd8dba507e85f116b1f7e231ca8525fc9008a6966",
"0x6571d97f340c8495b661a823f2c2145ca47d63c2",
...
]
istanbul-tools
to encode the .toml
as extraData
./build/bin/istanbul extra encode --config /path/to/conf.toml
extraData
field in istanbul-genesis.json
with output from the encoding If using QBFT
Find the 20-byte address representations of node 6 and node 7's nodekey (nodekeys located at qdata/dd{i}/geth/nodekey
). There are many ways to do this, one is to run a script making use of ethereumjs-wallet
:
const wlt = require('ethereumjs-wallet');
var nodekey = '1be3b50b31734be48452c29d714941ba165ef0cbf3ccea8ca16c45e3d8d45fb0';
var wallet = wlt.fromPrivateKey(Buffer.from(nodekey, 'hex'));
console.log('addr: ' + wallet.getAddressString());
istanbul-tools
to decode the extraData
field in qbft-genesis.json
git clone https://github.com/Consensys/istanbul-tools.git
cd istanbul-tools
make qbft
./build/bin/qbft extra decode --extradata <...>
.toml
file and update the formatting to the following:
vanity = "0x0000000000000000000000000000000000000000000000000000000000000000"
validators = [
"0xd8dba507e85f116b1f7e231ca8525fc9008a6966",
"0x6571d97f340c8495b661a823f2c2145ca47d63c2",
...
]
istanbul-tools
to encode the .toml
as extraData
./build/bin/qbft extra encode --config /path/to/conf.toml
extraData
field in qbft-genesis.json
with output from the encodingAfter making these changes, the relevant init/start scripts can be run (replace {consensus}
with the relevent consensus mechanism in the following):
# ./{consensus}-init.sh --numNodes 5
# ./{consensus}-start.sh
private-contract.js
by default sends a transaction to node 7. As node 7 will no longer be started this must be updated to instead send to node 5:
Copy node 5's public key from ./keys/tm5.pub
Replace the existing privateFor
in private-contract.js
with the key copied from tm5.pub
key, e.g.:
var simple = simpleContract.new(42, {from:web3.eth.accounts[0], data: bytecode, gas: 0x47b760, privateFor: ["R56gy4dn24YOjwyesTczYa8m5xhP6hF2uTMCju/1xkY="]}, function(e, contract) {...}
You can then follow steps described above to verify that node 5 can see the transaction payload and that nodes 2-4 are unable to see the payload.
Tessera v0.9 introduced the ability to run the privacy manager's enclave as a separate process from the Transaction Manager. This is a more secure way of being able to manage and interact with your keys.
To start a sample 7nodes network that uses remote enclaves run ./{consensus}-start.sh tessera-remote
. By default this will start 7 Transaction Managers, the first 4 of which use a remote enclave. If you wish to change this number, you will need to add the extra parameter --remoteEnclaves X
in the --tesseraOptions
, e.g. ./{consensus}-start.sh tessera-remote --tesseraOptions "--remoteEnclaves 7"
.
By default tessera uses the NaCl(salt) library in order to encrypt private payloads. If you would like to experiment with/use alternative curves/symmetric ciphers you can choose to configure the EC Encryptor (which relies on JCA to perform a similar logic to NaCl). The tessera initialization script uses the the following environment variables to generate the encryptor section of the tessera configuration file:
Environment Variable Name | Default Value | Description |
---|---|---|
ENCRYPTOR_TYPE | NACL | The encryptor type. Possible values are EC or NACL. |
ENCRYPTOR_EC_ELLIPTIC_CURVE | secp256r1 | The elliptic curve to use. See SunEC provider for other options. Depending on the JCE provider you are using there may be additional curves available. |
ENCRYPTOR_EC_SYMMETRIC_CIPHER | AES/GCM/NoPadding | The symmetric cipher to use for encrypting data (GCM IS MANDATORY as an initialisation vector is supplied during encryption). |
ENCRYPTOR_EC_NONCE_LENGTH | 24 | The nonce length (used as the initialization vector - IV - for symmetric encryption). |
ENCRYPTOR_EC_SHARED_KEY_LENGTH | 32 | The key length used for symmetric encryption (keep in mind the key derivation operation always produces 32 byte keys - so the encryption algorithm must support it). |
Based on the default values above (provided ENCRYPTOR_TYPE is defined as EC) the following configuration entry is produced:
...
"encryptor": {
"type":"EC",
"properties":{
"symmetricCipher":"AES/GCM/NoPadding",
"ellipticCurve":"secp256r1",
"nonceLength":"24",
"sharedKeyLength":"32"
}
}
...
Example:
export ENCRYPTOR_TYPE=EC
export ENCRYPTOR_EC_ELLIPTIC_CURVE=sect571k1
./raft-init.sh
Some simple transaction contracts are included in quorum-examples to demonstrate the privacy features of Quorum. To learn how to use them see the 7nodes README.
Stuck at some step? Please join our discord community for support.