Hyperledger Besu — Create a Private network: 5. Privacy-enabled network | Part I : Tessera

Raihan Hidayatullah Djunaedi
8 min readMay 2, 2024

Configuring a network that supports private transactions requires starting a Tessera node for each Hyperledger Besu node. Besu command line options associate the Besu node with the Tessera node.

This tutorial assumes you have completed setting up an IBFT 2.0 network to the point where you have created the genesis file and copied the private keys.

In this tutorial we start Tessera nodes for the four Besu nodes and associate each Besu node with a Tessera node.

Prerequisites

1. Create directories

Each node requires a data directory for the blockchain data.

Create directories for your private network, each of the four nodes, and a data directory for each node:

mkdir Privacy-Enable
cd Privacy-Enable/
mkdir -p Node-1/data
mkdir -p Node-2/data
mkdir -p Node-3/data
mkdir -p Node-4/data

2. Create a configuration file

Copy the following configuration file definition to a file called ibftConfigFile.json and save it in the Privacy-Enable directory:

touch ibftConfigFile.json
vi ibftConfigFile.json
{
"genesis": {
"config": {
"chainId": 1337,
"berlinBlock": 0,
"ibft2": {
"blockperiodseconds": 2,
"epochlength": 30000,
"requesttimeoutseconds": 4
}
},
"nonce": "0x0",
"timestamp": "0x58ee40ba",
"gasLimit": "0x47b760",
"difficulty": "0x1",
"mixHash": "0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365",
"coinbase": "0x0000000000000000000000000000000000000000",
"alloc": {
"fe3b557e8fb62b89f4916b721be55ceb828dbd73": {
"privateKey": "8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63",
"comment": "private key and this comment are ignored. In a real chain, the private key should NOT be stored",
"balance": "0xad78ebc5ac6200000"
},
"627306090abaB3A6e1400e9345bC60c78a8BEf57": {
"privateKey": "c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3",
"comment": "private key and this comment are ignored. In a real chain, the private key should NOT be stored",
"balance": "90000000000000000000000"
},
"f17f52151EbEF6C7334FAD080c5704D77216b732": {
"privateKey": "ae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f",
"comment": "private key and this comment are ignored. In a real chain, the private key should NOT be stored",
"balance": "90000000000000000000000"
}
}
},
"blockchain": {
"nodes": {
"generate": true,
"count": 4
}
}
}

then click esc, and type :wqto save and exit.

3. Generate node keys and a genesis file

In the Privacy-Enable directory, generate the node key and genesis file:

besu operator generate-blockchain-config --config-file=ibftConfigFile.json --to=networkFiles --private-key-file-name=key

Besu creates the following in the networkFiles directory:

  • genesis.json - The genesis file including the extraData property specifying the four nodes are validators.
  • A directory for each node named using the node address and containing the public and private key for each node.

4. Copy the genesis file to the Privacy-Enable directory

Move the genesis.json file to the Privacy-Enable directory.

cp networkFiles/genesis.json ../Privacy-Enable/

5. Copy the node private keys to the node directories

For each node, copy the key files to the data directory for that node

cp networkFiles/keys/<your first keys>/key Node-1/data/
cp networkFiles/keys/<your first keys>/key.pub Node-1/data/

cp networkFiles/keys/<your second keys>/key Node-2/data/
cp networkFiles/keys/<your second keys>/key.pub Node-2/data/

cp networkFiles/keys/<your third keys>/key Node-3/data/
cp networkFiles/keys/<your third keys>/key.pub Node-3/data/

cp networkFiles/keys/<your fourth keys>/key Node-4/data/
cp networkFiles/keys/<your fourth keys>/key.pub Node-4/data/

6. Create Tessera directories

Inside each Node-* directory, create a Tessera directory:

mkdir -p Node-1/Tessera
mkdir -p Node-2/Tessera
mkdir -p Node-3/Tessera
mkdir -p Node-4/Tessera

7. Generate Tessera keys

This example creates an unlocked private key, meaning you do not need a password to decrypt the private key file.

In each Tessera directory, generate a public/private key pair for the Tessera node:

cd Node-1/Tessera
tessera -keygen -filename nodeKey

cd Node-2/Tessera
tessera -keygen -filename nodeKey

cd Node-3/Tessera
tessera -keygen -filename nodeKey

cd Node-4/Tessera
tessera -keygen -filename nodeKey

At the prompt, press Enter to create an unlocked key.

Tessera generates the public/private key pair and saves the keys in the nodeKey.pub and nodeKey.key files.

8. Create Tessera configuration files

In the Tessera directory for each node, create a file called tessera.conf, with the following configuration:

  • Node-1
cd Node-1/Tessera
touch tessera.conf
vi tessera.conf
{
"mode": "orion",
"useWhiteList": false,
"jdbc": {
"username": "sa",
"password": "",
"url": "jdbc:h2:./target/h2/tessera1",
"autoCreateTables": true
},
"serverConfigs": [
{
"app": "ThirdParty",
"serverAddress": "http://localhost:9101",
"communicationType": "REST"
},
{
"app": "Q2T",
"serverAddress": "http://localhost:9102",
"communicationType": "REST"
},
{
"app": "P2P",
"serverAddress": "http://localhost:9103",
"sslConfig": {
"tls": "OFF"
},
"communicationType": "REST"
}
],
"peer": [
{
"url": "http://localhost:9203"
},
{
"url": "http://localhost:9303"
},
{
"url": "http://localhost:9403"
}
],
"keys": {
"passwords": [],
"keyData": [
{
"privateKeyPath": "nodeKey.key",
"publicKeyPath": "nodeKey.pub"
}
]
},
"alwaysSendTo": []
}

then click esc, and type :wqto save and exit.

  • Node-2
cd Node-2/Tessera
touch tessera.conf
vi tessera.conf
{
"mode": "orion",
"useWhiteList": false,
"jdbc": {
"username": "sa",
"password": "",
"url": "jdbc:h2:./target/h2/tessera1",
"autoCreateTables": true
},
"serverConfigs": [
{
"app": "ThirdParty",
"serverAddress": "http://localhost:9201",
"communicationType": "REST"
},
{
"app": "Q2T",
"serverAddress": "http://localhost:9202",
"communicationType": "REST"
},
{
"app": "P2P",
"serverAddress": "http://localhost:9203",
"sslConfig": {
"tls": "OFF"
},
"communicationType": "REST"
}
],
"peer": [
{
"url": "http://localhost:9103"
},
{
"url": "http://localhost:9303"
},
{
"url": "http://localhost:9403"
}
],
"keys": {
"passwords": [],
"keyData": [
{
"privateKeyPath": "nodeKey.key",
"publicKeyPath": "nodeKey.pub"
}
]
},
"alwaysSendTo": []
}

then click esc, and type :wqto save and exit.

  • Node-3
cd Node-3/Tessera
touch tessera.conf
vi tessera.conf
{
"mode": "orion",
"useWhiteList": false,
"jdbc": {
"username": "sa",
"password": "",
"url": "jdbc:h2:./target/h2/tessera1",
"autoCreateTables": true
},
"serverConfigs": [
{
"app": "ThirdParty",
"serverAddress": "http://localhost:9301",
"communicationType": "REST"
},
{
"app": "Q2T",
"serverAddress": "http://localhost:9302",
"communicationType": "REST"
},
{
"app": "P2P",
"serverAddress": "http://localhost:9303",
"sslConfig": {
"tls": "OFF"
},
"communicationType": "REST"
}
],
"peer": [
{
"url": "http://localhost:9103"
},
{
"url": "http://localhost:9203"
},
{
"url": "http://localhost:9403"
}
],
"keys": {
"passwords": [],
"keyData": [
{
"privateKeyPath": "nodeKey.key",
"publicKeyPath": "nodeKey.pub"
}
]
},
"alwaysSendTo": []
}

then click esc, and type :wqto save and exit.

  • Node-4
cd Node-4/Tessera
touch tessera.conf
vi tessera.conf
{
"mode": "orion",
"useWhiteList": false,
"jdbc": {
"username": "sa",
"password": "",
"url": "jdbc:h2:./target/h2/tessera1",
"autoCreateTables": true
},
"serverConfigs": [
{
"app": "ThirdParty",
"serverAddress": "http://localhost:9401",
"communicationType": "REST"
},
{
"app": "Q2T",
"serverAddress": "http://localhost:9402",
"communicationType": "REST"
},
{
"app": "P2P",
"serverAddress": "http://localhost:9403",
"sslConfig": {
"tls": "OFF"
},
"communicationType": "REST"
}
],
"peer": [
{
"url": "http://localhost:9103"
},
{
"url": "http://localhost:9203"
},
{
"url": "http://localhost:9303"
}
],
"keys": {
"passwords": [],
"keyData": [
{
"privateKeyPath": "nodeKey.key",
"publicKeyPath": "nodeKey.pub"
}
]
},
"alwaysSendTo": []
}

In the configuration file, specify:

  • Different port numbers for the various servers in the serverConfigs section.
  • The address of the Tessera nodes to discover, in the peer section.
  • The location of the public/private key pair.

4. Start the Tessera nodes

In each Tessera directory, start Tessera specifying the configuration file created in the previous step:

cd Node-1/Tessera
tessera -configfile tessera.conf

cd Node-2/Tessera
tessera -configfile tessera.conf

cd Node-3/Tessera
tessera -configfile tessera.conf

cd Node-4/Tessera
tessera -configfile tessera.conf

After starting the first Tessera node and before starting the other nodes, the log message failed to connect to node displays. This is normal behavior. Until you start the other peer nodes, your node is not connected and displays this warning. You can continue to start the other nodes.

5. Start Besu Node-1

In the Node-1 directory, start Besu Node-1:

cd Node-1
besu --data-path=data --genesis-file=../genesis.json --rpc-http-enabled --rpc-http-api=ETH,NET,IBFT,EEA,PRIV --host-allowlist="*" --rpc-http-cors-origins="all" --privacy-enabled --privacy-url=http://127.0.0.1:9102 --privacy-public-key-file=Tessera/nodeKey.pub --min-gas-price=0

The command line specifies privacy options:

When the node starts, the enode URL displays. Copy the enode URL to specify Node-1 as the bootnode in the following steps.

6. Start Besu Node-2

In the Node-2 directory, start Besu Node-2 specifying the Node-1 enode URL copied when starting Node-1 as the bootnode, Change <Node-1 Enode URL> with your enode:

cd Node-2
besu --data-path=data --genesis-file=../genesis.json --bootnodes=<Node-1 Enode URL> --p2p-port=30304 --rpc-http-enabled --rpc-http-api=ETH,NET,IBFT,EEA,PRIV --host-allowlist="*" --rpc-http-cors-origins="all" --rpc-http-port=8546 --privacy-enabled --privacy-url=http://127.0.0.1:9202 --privacy-public-key-file=Tessera/nodeKey.pub --min-gas-price=0

The command line specifies the same options as for Node-1 with different ports and Tessera node URL. The --bootnodes option specifies the enode URL of Node-1.

7. Start Besu Node-3

In the Node-3 directory, start Besu Node-3 specifying the Node-1 enode URL copied when starting Node-1 as the bootnode, Change <Node-1 Enode URL> with your enode:

cd Node-3
besu --data-path=data --genesis-file=../genesis.json --bootnodes=<Node-1 Enode URL> --p2p-port=30305 --rpc-http-enabled --rpc-http-api=ETH,NET,IBFT,EEA,PRIV --host-allowlist="*" --rpc-http-cors-origins="all" --rpc-http-port=8547 --privacy-enabled --privacy-url=http://127.0.0.1:9302 --privacy-public-key-file=Tessera/nodeKey.pub --min-gas-price=0

The command line specifies the same options as for Node-1 with different ports and Tessera node URL. The --bootnodes option specifies the enode URL of Node-1.

8. Start Besu Node-4

In the Node-4 directory, start Besu Node-4 specifying the Node-1 enode URL copied when starting Node-1 as the bootnode, Change <Node-1 Enode URL> with your enode:

cd Node-4
besu --data-path=data --genesis-file=../genesis.json --bootnodes=<Node-1 Enode URL> --p2p-port=30306 --rpc-http-enabled --rpc-http-api=ETH,NET,IBFT,EEA,PRIV --host-allowlist="*" --rpc-http-cors-origins="all" --rpc-http-port=8548 --privacy-enabled --privacy-url=http://127.0.0.1:9402 --privacy-public-key-file=Tessera/nodeKey.pub --min-gas-price=0

The command line specifies the same options as for Node-1 with different ports and Tessera node URL. The --bootnodes option specifies the enode URL of Node-1.

Reference : https://besu.hyperledger.org/private-networks/tutorials/privacy

--

--