
— a blockchain based on Ethereum, developed by JPMorgan, and recently becoming the first distributed ledger platform offered by Microsoft Azure.
Quorum supports both private and public transactions and has numerous commercial use cases.
In this article, we will explore one such scenario — deploying a distributed ledger network between a supermarket and a warehouse owner to ensure up-to-date information about the warehouse temperature.
The code used in this guide is located in .
This article covers:
- creating a smart contract;
- deploying a Quorum network using ;
- public transactions on Quorum;
- private transactions on Quorum.
The illustration uses a temperature monitoring scenario in the warehouse environments of Quorum network participants within the Internet of Things (IoT).
Context
A group of warehouse companies forms a consortium for joint information storage and process automation on the blockchain. To achieve this, the companies decided to use Quorum. In this article, we will cover two scenarios: public transactions and private transactions.
Transactions are created by different participants to interact with the consortium they belong to. Each transaction either deploys a contract or calls a function in the contract to upload data to the network. These actions are replicated across all nodes in the network.
Public transactions are accessible for viewing by all consortium participants. Private transactions add a layer of confidentiality and are only accessible to those participants who have permission.
For both scenarios, we use the same contract for illustration.
Smart Contract
Below is a simple smart contract created for our scenario. It has a public variable temperature, which can be changed using the method set and retrieved using the method get.
pragma solidity ^0.4.25;
contract TemperatureMonitor {
int8 public temperature;
function set(int8 temp) public {
temperature = temp;
}
function get() view public returns (int8) {
return temperature;
}
}For the contract to work with , it needs to be converted into ABI format and bytecode. Using the function formatContract, shown below, compiles the contract using .
function formatContract() {
const path = '.\/contracts\/temperatureMonitor.sol';
const source = fs.readFileSync(path,'UTF8');
return solc.compile(source, 1).contracts[':TemperatureMonitor'];
}The completed contract looks as follows:
// interface
[
{
constant: true,
inputs: [],
name: ‘get’,
outputs: [Array],
payable: false,
stateMutability: ‘view’,
type: ‘function’
},
{
constant: true,
inputs: [],
name: ‘temperature’,
outputs: [Array],
payable: false,
stateMutability: ‘view’,
type: ‘function’
},
{
constant: false,
inputs: [Array],
name: ‘set’,
outputs: [],
payable: false,
stateMutability: ‘nonpayable’,
type: ‘function’
}
]// bytecode
0x608060405234801561001057600080fd5b50610104806100206000396000f30060806040526004361060525763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416636d4ce63c81146057578063adccea12146082578063faee13b9146094575b600080fd5b348015606257600080fd5b50606960ae565b60408051600092830b90920b8252519081900360200190f35b348015608d57600080fd5b50606960b7565b348015609f57600080fd5b5060ac60043560000b60c0565b005b60008054900b90565b60008054900b81565b6000805491810b60ff1660ff199092169190911790555600a165627a7a72305820af0086d55a9a4e6d52cb6b3967afd764ca89df91b2f42d7bf3b30098d222e5c50029Now that the contract is ready, we will deploy the network and deploy the contract.
Node deployment

Node deployment can be quite labor-intensive, and this process can be replaced by using a service. .
Below is the process for deploying a Quorum network with Raft consensus and three nodes.
To start, let's create a project and name it Quorum Project:

We'll create a Quorum network with Raft consensus on Google Cloud Platform:

To the already created default node, we will add two more nodes:

Three running nodes:

The node details page shows the RPC endpoint, public key, etc.

The network is deployed. Now let's handle the deployment of smart contracts and executing transactions using .
Public transactions
Context
The temperature of the warehouse is crucial for reducing costs, especially for products meant to be stored at sub-zero temperatures.
By allowing companies to share the external temperature values of their geographic location in real-time and record them in an immutable ledger, network participants reduce expenses and time.

We will complete three tasks illustrated in the diagram:
We will deploy the contract via Node 1:
const contractAddress = await deployContract(raft1Node); console.log(`Contract address after deployment: ${contractAddress}`);We will set the temperature via Node 2 to 3 degrees:
const status = await setTemperature(raft2Node, contractAddress, 3); console.log(`Transaction status: ${status}`);Node 3 will retrieve information from the smart contract. The contract will return the value of 3 degrees:
const temp = await getTemperature(raft3Node, contractAddress); console.log('Retrieved contract Temperature', temp);Next, let's consider how to execute a public transaction in the Quorum network using .
We initiate an instance via RPC for three nodes:
const raft1Node = new Web3(
new Web3.providers.HttpProvider(process.env.RPC1), null, {
transactionConfirmationBlocks: 1,
},
);
const raft2Node = new Web3(
new Web3.providers.HttpProvider(process.env.RPC2), null, {
transactionConfirmationBlocks: 1,
},
);
const raft3Node = new Web3(
new Web3.providers.HttpProvider(process.env.RPC3), null, {
transactionConfirmationBlocks: 1,
},
);We will deploy the smart contract:
// returns the default account from the Web3 instance initiated previously
function getAddress(web3) {
return web3.eth.getAccounts().then(accounts => accounts[0]);
}
// Deploys the contract using contract's interface and node's default address
async function deployContract(web3) {
const address = await getAddress(web3);
// initiate contract with contract's interface
const contract = new web3.eth.Contract(
temperatureMonitor.interface
);
return contract.deploy({
// deploy contract with contract's bytecode
data: temperatureMonitor.bytecode,
})
.send({
from: address,
gas: '0x2CD29C0',
})
.on('error', console.error)
.then((newContractInstance) => {
// returns deployed contract address
return newContractInstance.options.address;
});
} provides two methods for interacting with the contract: call and send.
We will update the contract temperature by executing set using the web3 method send.
// get contract deployed previously
async function getContract(web3, contractAddress) {
const address = await getAddress(web3);
return web3.eth.Contract(
temperatureMonitor.interface,
contractAddress, {
defaultAccount: address,
}
);
}
// calls contract set method to update contract's temperature
async function setTemperature(web3, contractAddress, temp) {
const myContract = await getContract(web3, contractAddress);
return myContract.methods.set(temp).send({}).then((receipt) => {
return receipt.status;
});
}Next, we will use the web3 method call to retrieve the contract temperature. Note that the method call is executed on the local node and the transaction will not be created on the blockchain.
// calls contract get method to retrieve contract's temperature
async function getTemperature(web3, contractAddress) {
const myContract = await getContract(web3, contractAddress);
return myContract.methods.get().call().then(result => result);
}Now we can run to get the following result:
// Execute public script
node public.js
Contract address after deployment: 0xf46141Ac7D6D6E986eFb2321756b5d1e8a25008F
Transaction status: true
Retrieved contract Temperature 3Next, we can view the records in the Quorum explorer in the Chainstack panel, as shown below.
All three nodes interacted and the transactions have been updated:
- The first transaction deployed the contract.
- The second transaction set the contract temperature to 3 degrees.
- The temperature reading occurs through the local node, which is why the transaction was not created.

Private transactions
Context
A common requirement for organizations is data protection. For example, consider a scenario in which a supermarket rents a storage facility for seafood from a separate vendor.:
- Vendor Using IoT sensors, it reads temperature values every 30 seconds and transmits them to the supermarket.;
- These values should only be accessible to the vendor. and The supermarket, united in a consortium network.

We will perform four tasks illustrated in the diagram above.
- We will use the same three nodes from the previous scenario to demonstrate private transactions:
- The supermarket deploys a smart contract that is private to the supermarket. and vendor..
- A third party does not have access to the smart contract.
We will call methods get and set on behalf of the supermarket. and vendor. to demonstrate a Quorum private transaction.
We will deploy a private contract for participants The supermarket and Vendor through the participant The supermarket:
const contractAddress = await deployContract( raft1Node, process.env.PK2, ); console.log(`Contract address after deployment: ${contractAddress}`);We will set the temperature from the third party (external node) and receive the temperature value:
// Attempts to set Contract temperature to 10, this will not mutate contract's temperature await setTemperature( raft3Node, contractAddress, process.env.PK1, 10, ); // This returns null const temp = await getTemperature(raft3Node, contractAddress); console.log(`[Node3] temp retrieved after updating contract from external nodes: ${temp}`);We will set the temperature from vendor. (internal node) and receive the temperature value:
The temperature in this scenario should return a value of 12 from the smart contract. Note that Vendor this one has authorized access to the smart contract.
// Updated Contract temperature to 12 degrees await setTemperature( raft2Node, contractAddress, process.env.PK1, 12, ); // This returns 12 const temp2 = await getTemperature(raft2Node, contractAddress); console.log(`[Node2] temp retrieved after updating contract from internal nodes: ${temp2}`);We will get the temperature from the third party (external node):
At step 3, the temperature was set to 12, but A third party does not have access to the smart contract. Therefore, the returned value should be null.
// This returns null const temp3 = await getTemperature(raft3Node, contractAddress); console.log(`[Node3] temp retrieved from external nodes after update ${temp}`);Next, we will take a closer look at executing private transactions in the Quorum network with . Since the majority of the code matches public transactions, we will highlight only those parts that differ for private transactions.
Please note that the contract uploaded to the network is immutable, thus access permission must be granted to the relevant nodes by including the public contract at the time of contract deployment, not afterwards.
async function deployContract(web3, publicKey) {
const address = await getAddress(web3);
const contract = new web3.eth.Contract(
temperatureMonitor.interface,
);
return contract.deploy({
data: temperatureMonitor.bytecode,
})
.send({
from: address,
gas: '0x2CD29C0',
// Grant Permission to Contract by including nodes public keys
privateFor: [publicKey],
})
.then((contract) => {
return contract.options.address;
});
}Private transactions are executed similarly — by including the public key of participants at the time of execution.
async function setTemperature(web3, contractAddress, publicKey, temp) {
const address = await getAddress(web3);
const myContract = await getContract(web3, contractAddress);
return myContract.methods.set(temp).send({
from: address,
// Grant Permission by including nodes public keys
privateFor: [publicKey],
}).then((receipt) => {
return receipt.status;
});
}Now we can launch with the following results:
node private.js
Contract address after deployment: 0x85dBF88B4dfa47e73608b33454E4e3BA2812B21D
[Node3] temp retrieved after updating contract from external nodes: null
[Node2] temp retrieved after updating contract from internal nodes: 12
[Node3] temp retrieved from external nodes after update nullThe Quorum Explorer in Chainstack will show the following:
- contract deployment by participant The supermarket;
- Execution
SetTemperaturefrom the third party; - Execution
SetTemperatureby participant Vendor.

As you can see, both transactions were executed, but only the transaction from the participant Vendor updated the temperature in the contract. Thus, private transactions ensure immutability, while also not disclosing data to third parties.
Conclusion
We examined a commercial use case of Quorum to ensure up-to-date temperature information in a warehouse by deploying a network between two parties — a supermarket and a warehouse owner.
We demonstrated how up-to-date temperature information can be maintained through both public and private transactions.
There can be many application scenarios, and as you can see, it is quite simple.
Experiment and try to deploy your scenario. Moreover, the blockchain technology industry .
Source: habr.com
