使用Web3在JPMorgan Quorum区块链上执行公共和私人交易



Quorum是由JPMorgan开发的基于以太坊的区块链,最近成为Microsoft Azure提供的第一个分布式注册表平台。


Quorum支持私人和公共交易,并具有许多商业用例。


在本文中,我们将分析其中一种情况-在超级市场和仓库所有者之间部署分布式注册表网络,以提供有关仓库温度的相关信息。


本指南中使用的代码位于GitHub上存储库中


本文涵盖:


  • 建立智能合约;
  • 使用Chainstack部署Quorum网络
  • 法定公开交易
  • 法定私人交易。

为了说明这一点,我们将Quorum网络参与者的储藏室中的温度监控作为物联网(IoT)的一部分。


语境


一组仓库公司联合在一起组成一个联合体,用于信息的联合存储和区块链上流程的自动化。 为此,两家公司决定使用Quorum。 在本文中,我们将介绍两种情况:公共交易和私人交易。


交易是由不同的参与者创建的,以与它们所属的财团进行交互。 每个事务要么部署合同,要么调用合同中的功能以将数据上传到网络。 这些操作将复制到网络中的所有节点。


公开交易可供联盟的所有成员查看。 私人交易增加了一层保密性,并且仅对拥有此权利的参与者可用。


对于这两种情况,为清楚起见,我们使用相同的合同。


智能合约


以下是为我们的方案创建的简单智能合约。 它具有一个公共变量temperature ,可以使用set方法对其进行更改,并可以通过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; } } 

为了使合同能够与web3.js一起使用 ,必须将其转换为ABI格式和字节码。 使用下面的formatContract函数可使用solc-js编译合同。


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

完成的合同如下:


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

现在合同已经准备好了,我们将部署网络并部署合同。


节点部署


图片


部署节点可能会非常耗时,并且可以使用Chainstack服务来替换此过程。


以下是具有Raft共识和三个节点的Quorum网络部署过程。


首先,让我们开始一个项目并将其称为Quorum Project:


图片


在Google Cloud Platform上建立具有Raft共识的Quorum网络:


图片


在已经创建的默认节点上,再添加两个节点:


图片


三个运行节点:


图片


节点详细信息页面显示RPC端点,公共密钥等。


图片


网络已部署。 现在,我们将使用web3.js部署智能合约并执行交易。


公开交易


语境


仓库温度对于降低成本至关重要,尤其是对于打算在零以下温度下存储的产品而言。


通过使公司能够共享其地理位置的外部温度的实时值并将其记录在不变的注册表中,网络成员可以降低成本和时间。


图片


我们将完成图中所示的三个任务:


  1. 我们将通过节点1终止合同:


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

  2. 通过节点2将温度设置为3度:


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

  3. 节点3将接收来自智能合约的信息。 合同将返回3度的值:


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

    接下来,我们研究如何使用web3.js在Quorum网络上执行公共交易。



我们通过RPC为三个节点启动实例:


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

销毁智能合约:


 // 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提供了两种与合同进行交互的方法: callsend


通过使用web3 send方法执行set来更新合同的温度。


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

接下来,我们使用web3 call方法来获取合同的温度。 请注意, call方法在本地节点上执行,并且不会在区块链上创建交易。


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

现在,您可以运行public.js以获得以下结果:


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

接下来,我们可以在Chainstack面板的Quorum Explorer中看到条目,如下所示。


所有三个节点都进行了交互,并且交易已更新:


  1. 第一笔交易已获得合同。
  2. 第二笔交易将合同温度设置为3度。
  3. 温度是通过本地节点获得的,因此尚未创建事务。

图片


私人交易


语境


组织的共同要求是数据保护。 例如,考虑一个场景,其中一家超市租用了一个仓库来存储来自其他供应商的海鲜:


  • 供应商借助IoT传感器每30秒读取一次温度值,并将其传递给超市
  • 这些值仅对供应商超市 (网络联盟)可用。

图片


我们将完成上图中所示的四个任务。


  • 我们使用上一场景中的相同三个节点来演示私人交易:
  • 超级市场正在部署一个智能合约,该合约对于超级市场供应商是私有的。
  • 第三方无权访问智能合约。

我们将代表超市卖方调用getset方法,以演示私有Quorum交易。


  1. 我们将通过超级市场参与者终止与超级市场供应商参与者的私人合同:


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

  2. 第三方 (外部节点)设置温度并获取温度值:


     // 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. 供应商 (内部节点)设置温度并获取温度值:


    在这种情况下,温度应从智能合约恢复到12。请注意,此处的供应商已允许访问智能合约。


     // 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. 第三方 (外部节点)获取温度:


    在第3步中,温度设置为12,但是第三方无法访问智能合约。 因此,返回值必须为null。


     // This returns null const temp3 = await getTemperature(raft3Node, contractAddress); console.log(`[Node3] temp retrieved from external nodes after update ${temp}`); 

    接下来,我们将更详细地考虑使用web3.js在Quorum网络上执行私人交易。 由于大多数代码与公共交易一致,因此我们只选择与私人交易不同的部分。



请注意,上传到网络的合同是不可更改的,因此必须通过在部署合同时而不是之后将公共合同包括在内来授予相应节点的访问权限。


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

私人交易以相同的方式执行-通过在执行时包括参与者的公钥。


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

现在我们可以运行private.js并显示以下结果:


 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 

Chainstack的Quorum Explorer将显示以下内容:


  • 超市参与者的合同部署
  • 第三方执行SetTemperature ;
  • 供应商参与者执行SetTemperature

图片


如您所见,这两个事务都已完成,但是只有来自参与者供应商的事务才更新了合同中的温度。 因此,私人交易提供了不变性,但同时又不向第三方提供数据。


结论


我们研究了通过Quorum通过在两方之间(超级市场和仓库所有者)之间部署网络来在仓库中提供最新温度信息的商业方案。


我们已经展示了如何通过公共和私人交易维护当前的温度信息。


您可以看到很多应用程序场景,这并不困难。


实验,尝试部署您的脚本。 此外,到2024年 ,区块链技术行业的增长将近十倍

Source: https://habr.com/ru/post/zh-CN456368/


All Articles