
— блокчейн на база Ethereum, разработен от JPMorgan и наскоро станал първата платформа за разпределен регистър, предлагана от Microsoft Azure.
Кворум поддържа частни и публични транзакции и има много търговски сценарии за използване.
В тази статия ще разгледаме един от тези сценарии — разгръщането на мрежа за разпределен регистър между супермаркет и собственик на склад за осигуряване на актуална информация за температурата в склада.
Кодът, използван в това ръководство, се намира в .
Статията обхваща:
- създаване на смарт-контракт;
- разгръщане на мрежа Кворум с помощта на ;
- публични транзакции на Кворум;
- частни транзакции на Кворум.
За илюстрация се използва сценарий за мониторинг на температурата в складовете на участниците в мрежата Кворум в рамките на Интернет на нещата (IoT).
Контекст
Група складови компании се обединяват в консорциум за съвместно съхраняване на информация и автоматизация на процесите в блокчейна. Затова компаниите решиха да използват Кворум. В тази статия ще покрием два сценария: публични транзакции и частни транзакции.
Транзакциите се създават от различни участници за взаимодействие с консорциума, към който принадлежат. Всяка транзакция или деплоит контракт, или извиква функция в контракта за зареждане на данни в мрежата. Тези действия се реплицират на всички възли в мрежата.
Публичните транзакции са достъпни за преглед от всички участници в консорциума. Частните транзакции добавят слой на конфиденциалност и са достъпни само за тези участници, които имат права за достъп.
За двата сценария използваме един и същ контракт за наглядност.
Смарт-контракт
По-долу е представен прост смарт-контракт, създаден за нашия сценарий. В него има публична променлива 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 с . Тъй като по-голямата част от кода съвпада с публичните транзакции, ще подчертаем само тези части, които се различават за приватните транзакции.
Имайте предвид, че договорът, качен в мрежата, е неизменяем, затова достъп с разрешение (permissioned) трябва да бъде предоставен на съответните възли чрез включване на публичния договор по време на разгръщането му, а не след това.
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
Договорен адрес след разгръщането: 0x85dBF88B4dfa47e73608b33454E4e3BA2812B21D
[Node3] температура получена след актуализиране на договора от външни възли: null
[Node2] температура получена след актуализиране на договора от вътрешни възли: 12
[Node3] температура получена от външни възли след актуализация nullQuorum Explorer в Chainstack ще покаже следното:
- разгръщане на договора от участника Супермаркет;
- Изпълнение
SetTemperatureот Третата страна; - Изпълнение
SetTemperatureот участника Вендор.

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