
— блокчейн, базиран на Ethereum, разработен от JPMorgan и наскоро стана първата платформа за разпределени регистри, която предлага Microsoft Azure.
Quorum поддържа частни и публични транзакции и има много търговски сценарии за използване.
В тази статия ще разгледаме един от тези сценарии — разгръщането на мрежа за разпределен регистър между супермаркет и собственик на склад за осигуряване на актуална информация за температурата в складовото помещение.
Кодът, използван в това ръководство, е .
Статията обхваща:
- създаване на смарт-контракт;
- разгръщане на мрежа Quorum с помощта на ;
- публични транзакции в Quorum;
- частни транзакции в Quorum.
За илюстрация се използва сценарий за мониторинг на температурата в складовите помещения на участниците в мрежата Quorum в рамките на Internet of Things (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;
}
}За да работи контрактът с , той трябва да бъде преобразуван в формат ABI и байткод. Използването на функцията 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Сега, когато договора е готов, ще разположим мрежата и ще разположим договора.
Разполагане на нодове

Разполагането на нода може да бъде доста трудоемко и този процес може да бъде заменен с използването на услуга. .
По-долу е представен процесът на разполагане на мрежата Quorum с консенсус Raft и три нода.
Първо, ще създадем проект и ще го наречем Quorum Project:

Ще създадем мрежа Quorum с консенсус Raft в Google Cloud Platform:

Към вече създадения по подразбиране нод ще добавим още два нода:

Три активни нода:

Страница с детайли на нода показва RPC endpoint, публичен ключ и т.н.

Мрежата е разположена. Сега ще се заемем с деплойването на смарт-договори и изпълнението на транзакции с помощта на .
Публични транзакции
Контекст
Температурата на складовото помещение има голямо значение за намаляване на разходите, особено за продукти, които трябва да се съхраняват при отрицателни температури.
Предоставяйки на компаниите възможността да споделят стойностите на външната температура на географското си местоположение в реално време и да записват в неизменим регистър, участниците в мрежата намаляват разходите и времето.

Ще извършим три задачи, илюстрирани в диаграмата:
Ще разположим договора чрез Node 1:
const contractAddress = await deployContract(raft1Node); console.log(`Адрес на договора след разполагането: ${contractAddress}`);Ще зададем температурата чрез Node 2 с 3 градуса:
const status = await setTemperature(raft2Node, contractAddress, 3); console.log(`Статус на транзакцията: ${status}`);Node 3 ще получи информация от смарт-договора. Договорът ще върне стойност 3 градуса:
const temp = await getTemperature(raft3Node, contractAddress); console.log('Получена температура от договора', temp);Нека разгледаме как да изпълним публична транзакция в мрежата 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;
});
} осигурява два метода за взаимодействие с договора: 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Следва да разгледаме записките в експлорера Quorum в панела на Chainstack, както е показано по-долу.
Всички три ноди взаимодействат и транзакциите се обновяват:
- Първата транзакция деплоизира контракта.
- Втората транзакция зададе температурата на контракта на 3 градуса.
- Получаването на температурата се извършва през локалната нода, затова транзакция не е създадена.

Приватни транзакции
Контекст
Често изискване на организациите е защита на данните. Като пример разглеждаме сценарий, в който Супермаркет наема складово помещение за съхранение на морски дарове от отделен Доставчик:
- Доставчик чрез IoT-сензори счита температурните стойности на всеки 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, но Третата страна няма достъп до смарт-контракта. Следователно връщането на стойността трябва да бъде null.
// This returns null const temp3 = await getTemperature(raft3Node, contractAddress); console.log(`[Node3] temp retrieved from external nodes after update ${temp}`);Следва да разгледаме по-подробно изпълнението на приватни транзакции в мрежата 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;
});
}Сега можем да стартираме с следните резултати:
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 nullExplorer Quorum в Chainstack ще покаже следното:
- деплой на договора от участник Супермаркет;
- Изпълнение
SetTemperatureот Третата страна; - Изпълнение
SetTemperatureот участник Доставчик.

Както виждате, и двете транзакции са изпълнени, но само транзакцията от участника Доставчик обнови температурата в договора. По този начин частните транзакции осигуряват неизменяемост, но също така не разкриват данни на трети страни.
Заключение
Ние разгледахме търговски сценарий за използване на Quorum за осигуряване на актуална информация за температурата в складово помещение чрез разгръщане на мрежа между две страни — хипермаркет и собственик на склад.
Показахме как актуалната информация за температурата може да се поддържа както чрез публични, така и чрез частни транзакции.
Приложенията може да са много и, както виждате, това не е никак сложно.
Експериментирайте, опитайте се да разположите своя сценарий. Особено, тъй като индустрията на блокчейн технологиите .
Източник: habr.com
