How to Send Private Transactions


Private Transaction Managers allow to send transactions to a subset of nodes in a private blockchain. This means that only nodes that are party to a given private transaction will be able to view the contents of it.

Private Transaction Manager

Enterprise ready Ethereum clients, such as Hyperledger Besu (formerly named Pantheon) and Quorum, allow to send private transactions through their Enterprise Tx Managers.

Hyperledger Besu’s Enterprise Tx Manager Orion.

Quorum’s Enterprise Tx Managers are Constellation and Tessera.

Private Tx parameters

The following parameters are exclusive for Private Transactions with any Tx Manager:

  • privateFor: array[PublicKeys] of the nodes that take part on the Private Transaction.
  • privateFrom: DATA, 20 bytes – For private transactions, the public key of the sender.

When using Hyperledger Besu’s Tx Manager, Orion

When using Hyperledger Besu’s Tx Manager, Orion, to send a private transaction, Orchestrate first signs the transaction and then sends it to Hyperledger Besu using web3 API. We will need to declare the following variable:

  • privateTxType: STRING – If value is restricted, the transaction is a restricted private transaction. If unrestricted, the transaction is an unrestricted private transaction. This parameter is equivalent to the parameter called restricted on EEA documentation.

When using Quorum’s Tx Manager Tessera

When using Quorum’s Tx Manager Tessera, Orchestrate does the following:

  1. Sends the data field of the transaction to Tessera directly. Tessera will store the data and will return a hash of the transaction’s data field;
  2. Orchestrate receives the hash from Tessera and replaces the value of the transaction’s data field with the received hash. From now on Orchestrate works with a transaction where the actual data is replaced with the hash received from Tessera.
  3. The transaction (with a hash instead of the data field) is now signed by Orchestrate and sent to Quorum using the web3 API.

To use Tessera we need to use the sendRawPrivateTransaction method. Quorum’s API documentation can be found here.


Note that Quorum and Tessera are two different processes and they communicate with each other via the network. To get a hash for a private transaction Orchestrate needs to send the transaction’s data directly to the Tessera process. Tessera endpoint is different from a regular web3 endpoint that we use for public transactions.

Orchestrate & Tessera

If we are connecting Orchestrate to multiple chains, we will need to provide a separate Tessera endpoint for each chain id. In order to indicate this mapping we need to use the TESSERA_ENDPOINTS env. variable as follows:

export TESSERA_ENDPOINTS='{"10":"http://txmanager1:9080", "12":"http://txmanager2:9081"}'

In this case, we are connecting to 2 chains, and we specify that for chain id 10 the endpoint to use is http://txmanager1:9080 and for chain id 12 the endpoint to use is http://txmanager2:9081.


TESSERA_ENDPOINTS is a JSON object. You can check more info here.

Sending private transactions to a subgroup of nodes

  try {
            const tx = await producer.send({
                chainId: 10,
                protocol: {
                    type: 'ProtocolType.QuorumTessera',
     const tx = await producer.send({
                chainId: 10,
                protocol: {
                    type: ProtocolType.QuorumTessera,
                to: '0xe5ce65038f9d1c841a33cc816ee674f8a0e31e74',
                call: {
                    // contract: 'SimpleToken',
                    // method: 'constructor()'
                    method: 'transfer(address,uint256)',
                    args: ["0xdbb881a51cd4023e4400cef3ef73046743f08da3", "100000"]
                privateFor: ['BULeR8JyUWhiuuCMU/HLA0Q5pzkYT+cHII3ZKBey3Bo=', 'QfeDAys9MPDs2XHExtc84jKGHxZg/aj52DTh0vtA3Xc='],
                privateFrom: 'BULeR8JyUWhiuuCMU/HLA0Q5pzkYT+cHII3ZKBey3Bo=',
                gas: 2000000,
                gasPrice: 0,
                value: 0,
                from: '0x7e654d251da770a068413677967f6d3ea2fea9e4'