Performing public and private transactions on the JPMorgan Quorum blockchain using Web3

Performing public and private transactions on the JPMorgan Quorum blockchain using Web3

Quorum is an Ethereum-based blockchain developed by JPMorgan and most recently the first distributed ledger platform offered by Microsoft Azure.

Quorum supports private and public transactions and has many commercial use cases.

In this article, we will analyze one of these scenarios - deploying a distributed ledger network between a supermarket and a warehouse owner to provide up-to-date information about the temperature of a warehouse.

The code used in this manual is in repositories on GitHub.

The article covers:

  • creation of a smart contract;
  • Deploying a Quorum network using Chainstack;
  • Quorum public transactions;
  • Quorum private transactions.

For illustration, the scenario of monitoring the temperature in warehouses of Quorum network participants within the Internet of Things (IoT) is used.

Context

A group of warehouse companies unites into a consortium to jointly store information and automate processes on the blockchain. For this, companies have 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 to all nodes in the network.

Public transactions are available for viewing by all members of the consortium. Private transactions add a layer of privacy and are available only to those participants who have the right to do so.

For both scenarios, we use the same contract for clarity.

Smart contract

Below is a simple smart contract created for our scenario. It has a public variable temperature, which can be changed by the method set and receive 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;
  }
}

In order for the contract to work with web3.js, it needs to be converted to ABI format and bytecode. Function use formatContractbelow compiles the contract with solc-js.

function formatContract() {
  const path = './contracts/temperatureMonitor.sol';
  const source = fs.readFileSync(path,'UTF8');
return solc.compile(source, 1).contracts[':TemperatureMonitor'];
}

The finished contract looks like this:

// 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
0x608060405234801561001057600080fd5b50610104806100206000396000f30060806040526004361060525763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416636d4ce63c81146057578063adccea12146082578063faee13b9146094575b600080fd5b348015606257600080fd5b50606960ae565b60408051600092830b90920b8252519081900360200190f35b348015608d57600080fd5b50606960b7565b348015609f57600080fd5b5060ac60043560000b60c0565b005b60008054900b90565b60008054900b81565b6000805491810b60ff1660ff199092169190911790555600a165627a7a72305820af0086d55a9a4e6d52cb6b3967afd764ca89df91b2f42d7bf3b30098d222e5c50029

Now that the contract is ready, we will deploy the network and deploy the contract.

Node Deployment

Performing public and private transactions on the JPMorgan Quorum blockchain using Web3

Deploying a node can be quite time consuming and this process can be replaced by using a service Chainstack.

Below is the process of deploying a Quorum network with Raft consensus and three nodes.

First, let's start a project and call it Quorum Project:

Performing public and private transactions on the JPMorgan Quorum blockchain using Web3

Let's create a Quorum network with Raft consensus on the Google Cloud Platform:

Performing public and private transactions on the JPMorgan Quorum blockchain using Web3

Let's add two more nodes to the node already created by default:

Performing public and private transactions on the JPMorgan Quorum blockchain using Web3

Three running nodes:

Performing public and private transactions on the JPMorgan Quorum blockchain using Web3

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

Performing public and private transactions on the JPMorgan Quorum blockchain using Web3

The network is deployed. Now let's deal with the deployment of smart contracts and the execution of transactions using web3.js.

Public transactions

Context

The temperature of the storage room is of great importance to reduce costs, especially for products intended for storage at sub-zero temperatures.

By enabling companies to share real-time outside temperatures of their geographic location and record them in an immutable register, network members reduce costs and time.

Performing public and private transactions on the JPMorgan Quorum blockchain using Web3

We will perform three tasks illustrated in the diagram:

  1. Let's deploy the contract through Node 1:

    const contractAddress = await deployContract(raft1Node);
    console.log(`Contract address after deployment: ${contractAddress}`);

  2. Set the temperature via Node 2 by 3 degrees:

    const status = await setTemperature(raft2Node, contractAddress, 3);
    console.log(`Transaction status: ${status}`);

  3. Node 3 will receive information from the smart contract. The contract will return a value of 3 degrees:

    const temp = await getTemperature(raft3Node, contractAddress);
    console.log(‘Retrieved contract Temperature’, temp);

    Next, let's look at how to execute a public transaction on the Quorum network using web3.js.

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,
 },
);

Let's deploy a 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;
  });
}

web3.js provides two methods for interacting with the contract: call и send.

Update the temperature of the contract by executing set using 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 use the web3 method call to get the contract temperature. Please note that the method call is executed on the local node and no transaction will 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 you can run public.js to get the following result:

// Execute public script
node public.js
Contract address after deployment: 0xf46141Ac7D6D6E986eFb2321756b5d1e8a25008F
Transaction status: true
Retrieved contract Temperature 3

Next, we can look at the records in the Quorum explorer in the Chainstack panel, as shown below.

All three nodes interacted and transactions were updated:

  1. The first transaction deployed the contract.
  2. The second transaction set the contract temperature to 3 degrees.
  3. The temperature is received through the local node, so the transaction is not created.

Performing public and private transactions on the JPMorgan Quorum blockchain using Web3

Private transactions

Context

Data protection is a frequent requirement of organizations. As an example, consider a scenario in which Supermarket rents a warehouse for storing seafood from a separate Vendor:

  • Vendor using IoT sensors reads temperature values ​​every 30 seconds and transmits them Supermarket;
  • these values ​​should only be available Vendor и Supermarketnetworked by a consortium.

Performing public and private transactions on the JPMorgan Quorum blockchain using Web3

We will complete the four tasks illustrated in the diagram above.

  • Let's use the same three nodes from the previous scenario to demonstrate private transactions:
  • Supermarket deploys a smart contract that is private to supermarket и Vendor.
  • The third side does not have the right to access the smart contract.

We will call the methods get и set on behalf of supermarket и Vendor to demonstrate a Quorum private transaction.

  1. Deploy a private contract for participants Supermarket и Vendor through a member Supermarket:

    const contractAddress = await deployContract(
    raft1Node,
    process.env.PK2,
    );
    console.log(`Contract address after deployment: ${contractAddress}`);

  2. Set the temperature from third party (external node) and get 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}`);

  3. Set the temperature from Vendor (internal node) and get the temperature value:

    The temperature in this scenario should return the value 12 from the smart contract. Please note that Vendor here 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}`);

  4. Get temperature from third party (external node):

    In step 3, the temperature was set to 12, but The third side does not have access to the smart contract. So the return 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 the execution of private transactions in the Quorum network with web3.js. Since most of the code is the same as public transactions, we will highlight only those parts that are different for private transactions.

Please note that the contract uploaded to the network is immutable, so permissioned access must be granted to the appropriate nodes by including the public contract at the time the contract is deployed, and not after.

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;
  });
}

Similarly, private transactions are performed by including the public key of the 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 run private.js 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 null

Quorum explorer in Chainstack will show the following:

  • deployment of the contract from the participant Supermarket;
  • Performance SetTemperature from third party;
  • Performance SetTemperature from participant Vendor.

Performing public and private transactions on the JPMorgan Quorum blockchain using Web3

As you can see, both transactions are completed, but only the transaction from the participant Vendor updated the temperature in the contract. Thus, private transactions provide immutability, but at the same time they do not give out data to a third party.

Conclusion

We looked at a commercial use case for Quorum to provide up-to-date information about the temperature in a warehouse by deploying a network between two parties - a supermarket and a warehouse owner.

We have shown how up-to-date temperature information can be maintained through both public and private transactions.

There can be a lot of application scenarios and, as you can see, it is not at all difficult.

Experiment, try deploying your scenario. Moreover, the blockchain technology industry by 2024 could grow almost tenfold.

Source: habr.com

Add a comment