Quorum 支持私人和公共交易,并且有许多商业用例。
在本文中,我们将研究一个这样的场景 - 在超市和仓库所有者之间部署分布式账本网络,以提供有关仓库温度的最新信息。
本教程中使用的代码位于
文章涵盖:
- 创建智能合约;
- 使用 Quorum 网络的部署
链栈 ; - 法定人数公开交易;
- 法定私人交易。
为了说明这一点,我们使用一个场景来监控物联网 (IoT) 内 Quorum 网络成员仓库的温度。
上下文
一群仓储公司正在联合组成一个联盟,共同在区块链上存储信息并实现流程自动化。为此,公司决定使用 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;
}
}
为了使合同能够与 formatContract
下面使用编译合同
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
0x608060405234801561001057600080fd5b50610104806100206000396000f30060806040526004361060525763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416636d4ce63c81146057578063adccea12146082578063faee13b9146094575b600080fd5b348015606257600080fd5b50606960ae565b60408051600092830b90920b8252519081900360200190f35b348015608d57600080fd5b50606960b7565b348015609f57600080fd5b5060ac60043560000b60c0565b005b60008054900b90565b60008054900b81565b6000805491810b60ff1660ff199092169190911790555600a165627a7a72305820af0086d55a9a4e6d52cb6b3967afd764ca89df91b2f42d7bf3b30098d222e5c50029
现在合约已经准备好了,我们将部署网络并部署合约。
节点部署
部署节点可能是相当耗费人力的,这个过程可以通过使用服务来替代
下面是部署具有 Raft 共识和三个节点的 Quorum 网络的流程。
首先,我们创建一个项目并将其命名为 Quorum Project:
让我们在 Google Cloud Platform 上创建一个具有 Raft 共识的 Quorum 网络:
让我们在默认创建的节点上再添加两个节点:
三个运行节点:
节点详细信息页面显示RPC端点、公钥等。
网络已部署。现在让我们部署智能合约并使用以下命令执行交易
公开交易
上下文
仓库温度对于降低成本非常重要,特别是对于打算在零度以下储存的产品。
通过允许公司实时共享其地理位置的外部温度并将其记录在不可变的分类账中,网络参与者可以降低成本和时间。
我们将执行三项任务,如图所示:
-
我们将通过以下方式部署合约 节点1:
const contractAddress = await deployContract(raft1Node); console.log(`Contract address after deployment: ${contractAddress}`);
-
通过设置温度 节点2 3度:
const status = await setTemperature(raft2Node, contractAddress, 3); console.log(`Transaction status: ${status}`);
-
节点3 将从智能合约接收信息。合约将返回 3 度的值:
const temp = await getTemperature(raft3Node, contractAddress); console.log(‘Retrieved contract Temperature’, temp);
接下来,我们将了解如何使用 Quorum 网络上执行公共交易
web3.js .
我们通过 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;
});
}
call
и send
.
让我们通过执行来更新合约温度 set
使用web3方法 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;
});
}
接下来我们使用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);
}
现在你可以运行
// Execute public script
node public.js
Contract address after deployment: 0xf46141Ac7D6D6E986eFb2321756b5d1e8a25008F
Transaction status: true
Retrieved contract Temperature 3
接下来,我们可以在Chainstack面板的Quorum explorer中查看条目,如下所示。
所有三个节点进行交互并更新交易:
- 第一个交易部署了合约。
- 第二笔交易将合约温度设置为3度。
- 温度是通过本地节点接收的,因此不会创建事务。
私人交易
上下文
组织的一个共同要求是数据保护。举个例子,考虑这样一个场景: 超级市场 租用一个单独的仓库来储存海鲜 小贩:
- 小贩 使用物联网传感器,每30秒读取一次温度值并传输 去超市;
- 这些值应该只可用 致供应商 и 去超市,由一个联盟联网。
我们将完成上图中所示的四个任务。
- 我们使用与上一个场景相同的三个节点来演示私有交易:
- 超级市场 部署一个私有的智能合约 超级市场 и 小贩.
- 第三面 无权访问智能合约。
我们将调用这些方法 get
и set
代表 超级市场 и 小贩 演示私人 Quorum 交易。
-
我们将为参与者部署一个私人合约 超级市场 и 小贩 通过一个参与者 超级市场:
const contractAddress = await deployContract( raft1Node, process.env.PK2, ); console.log(`Contract address after deployment: ${contractAddress}`);
-
让我们将温度设置为 第三者 (外部节点)并获取温度值:
// 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}`);
-
让我们将温度设置为 小贩 (内部节点)并获取温度值:
此场景中的温度应从智能合约返回值 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}`);
-
我们得到的温度来自 第三者 (外部节点):
在步骤 3 中,温度设置为 12,但是 第三面 无权访问智能合约。因此返回值必须为空。
// This returns null const temp3 = await getTemperature(raft3Node, contractAddress); console.log(`[Node3] temp retrieved from external nodes after update ${temp}`);
接下来,我们将仔细研究在 Quorum 网络上执行私人交易
web3.js 。由于公共交易的大部分代码是相同的,因此我们将仅突出显示私人交易中不同的部分。
请注意,上传到网络的合约是不可变的,因此必须在部署合约时(而不是之后)通过启用公共合约来向适当的节点授予许可访问权限。
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;
});
}
现在我们可以运行
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 浏览器将显示以下内容:
- 参与者部署合约 超级市场;
- 执行
SetTemperature
从 第三者; - 执行
SetTemperature
来自参与者 小贩.
可以看到,两笔交易都完成了,但是只有参与者的交易 小贩 更新了合同中的温度。因此,私人交易提供了不变性,但同时不会向第三方泄露数据。
结论
我们研究了 Quorum 的一个商业用例,通过在超市和仓库所有者两方之间部署网络来提供仓库中的最新温度信息。
我们展示了如何通过公共和私人交易来维护最新的温度信息。
应用场景可以有很多,正如你所看到的,一点也不困难。
实验,尝试扩展你的脚本。此外,区块链技术产业
来源: habr.com