
— o platformă blockchain bazată pe Ethereum, dezvoltată de JPMorgan și recent devenită prima platformă de registru distribuit oferită de Microsoft Azure.
Quorum sprijină atât tranzacții private, cât și publice, având multe scenarii comerciale de utilizare.
În acest articol, vom analiza unul dintre aceste scenarii — desfășurarea unei rețele de registru distribuit între un supermarket și un proprietar de depozit pentru a asigura informații actualizate despre temperatura spațiului de depozitare.
Codul utilizat în acest ghid se află în .
Articolul acoperă:
- crearea unui smart contract;
- desfășurarea rețelei Quorum folosind ;
- tranzacții publice Quorum;
- tranzacții private Quorum.
Pentru ilustrarea folosită, se utilizează un scenariu de monitorizare a temperaturii în depozitele participanților la rețeaua Quorum în cadrul Internet of Things (IoT).
Context
Un grup de companii de depozit se unește într-un consorțiu pentru a stoca informații în comun și a automatiza procesele pe blockchain. Pentru aceasta, companiile au decis să folosească Quorum. În acest articol, vom acoperi două scenarii: tranzacții publice și tranzacții private.
Tranzacțiile sunt create de diferiți participanți pentru a interacționa cu consorțiul din care fac parte. Fiecare tranzacție fie desfășoară un contract, fie apelează o funcție în contract pentru a încărca date în rețea. Aceste acțiuni sunt replicate pe toate nodurile din rețea.
Tranzacțiile publice sunt disponibile pentru vizualizare de către toți participanții consorțiului. Tranzacțiile private, pe de altă parte, adaugă un strat de confidențialitate și sunt disponibile doar acelora participanți care au drepturile necesare.
Pentru ambele scenarii, folosim același contract pentru claritate.
Contract inteligent
Mai jos este un smart contract simplu, creat pentru scenariul nostru. Acesta conține o variabilă publică temperature, care poate fi modificată prin metoda set 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; } } get.
Pentru ca acest contract să funcționeze cu, trebuie să fie convertit în format ABI și bytecode. Utilizarea funcției formatContract , prezentată mai jos, compilează contractul folosindsolc-js .
function formatContract() {
const path = './contracts/temperatureMonitor.sol';
const source = fs.readFileSync(path,'UTF8');
return solc.compile(source, 1).contracts[':TemperatureMonitor'];
}Contractul finalizat arată astfel:
// 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
0x608060405234801561001057600080fd5b50610104806100206000396000f30060806040526004361060525763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416636d4ce63c81146057578063adccea12146082578063faee13b9146094575b600080fd5b348015606257600080fd5b50606960ae565b60408051600092830b90920b8252519081900360200190f35b348015608d57600080fd5b50606960b7565b348015609f57600080fd5b5060ac60043560000b60c0565b005b60008054900b90565b60008054900b81565b6000805491810b60ff1660ff199092169190911790555600a165627a7a72305820af0086d55a9a4e6d52cb6b3967afd764ca89df91b2f42d7bf3b30098d222e5c50029Acum că contractul este pregătit, vom desfășura rețeaua și vom implementa contractul.
Implementarea nodurilor

Desfășurarea nodului poate fi destul de laborioasă și acest proces poate fi înlocuit prin utilizarea unui serviciu. .
Mai jos este procesul de desfășurare a rețelei Quorum cu consensul Raft și trei noduri.
Pentru început, să începem un proiect și să-l numim Quorum Project:

Să creăm o rețea Quorum cu consensul Raft pe Google Cloud Platform:

La nodul creat implicit, vom adăuga încă două noduri:

Cele trei noduri active:

Pagina detaliilor nodului arată endpoint-ul RPC, cheia publică etc.

Rețeaua este desfășurată. Acum să ne ocupăm de implementarea smart contractelor și efectuarea tranzacțiilor prin .
Tranzacții publice
Context
Temperatura din încăperile de depozitare este foarte importantă pentru reducerea costurilor, în special pentru produsele care trebuie păstrate la temperaturi negative.
Oferind companiilor posibilitatea de a împărtăși valorile temperaturii externe a locației lor geografice în timp real și de a le înregistra într-un registru imuabil, participanții la rețea reduc cheltuielile și timpul.

Vom îndeplini trei sarcini, ilustate în diagrama:
Vom implementa contractul prin Nodul 1:
const contractAddress = await deployContract(raft1Node); console.log(`Adresa contractului după desfășurare: ${contractAddress}`);Să setăm temperatura prin Nodul 2 la 3 grade:
const status = await setTemperature(raft2Node, contractAddress, 3); console.log(`Statusul tranzacției: ${status}`);Nodul 3 va obține informații de la smart contract. Contractul va returna valoarea de 3 grade:
const temp = await getTemperature(raft3Node, contractAddress); console.log('Temperatura contractului recuperată', temp);Mai departe, să vedem cum se execută o tranzacție publică în rețeaua Quorum folosind .
Inițiem o instanță prin RPC pentru cele trei noduri:
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,
},
);Vom implementa smart contractul:
// 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;
});
} oferă două metode pentru interacțiunea cu contractul: call și send.
Vom actualiza temperatura contractului prin executarea set folosind metoda 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;
});
}Apoi, folosim metoda web3 call pentru a obține temperatura contractului. Rețineți că metoda call se execută pe nodul local și tranzacția nu va fi creată pe 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);
}Acum putem rula pentru a obține următorul rezultat:
// Execute public script
node public.js
Contract address after deployment: 0xf46141Ac7D6D6E986eFb2321756b5d1e8a25008F
Transaction status: true
Retrieved contract Temperature 3Apoi, putem vizualiza înregistrările în exploratorul Quorum în panoul Chainstack, așa cum este prezentat mai jos.
Toate cele trei noduri au interacționat și tranzacțiile s-au actualizat:
- Prima tranzacție a desfășurat contractul.
- A doua tranzacție a setat temperatura contractului la 3 grade.
- Obținerea temperaturii se face prin nodul local, deci tranzacția nu a fost creată.

Tranzacții private
Context
O cerință des întâlnită a organizațiilor este protecția datelor. Ca exemplu, să luăm în considerare un scenariu în care un supermarket închiriază un depozit pentru stocarea produselor marine de la un vendor:
- vendor prin intermediul senzorilor IoT care citesc valorile de temperatură la fiecare 30 de secunde și le transmit supermarketului;
- aceste valori ar trebui să fie accesibile doar vendorului și supermarketului, care sunt unite într-o rețea de consorțiu.

Vom îndeplini patru sarcini, ilustate în diagrama de mai sus.
- Folosim aceleași trei noduri din scenariul anterior pentru a demonstra tranzacțiile private:
- Supermarketul desfășoară un smart contract care este privat pentru supermarket. și vendor.
- O terță parte nu are dreptul de acces la smart contract.
Vom apela metodele get și set în numele supermarket. și vendor pentru a demonstra tranzacția privată Quorum.
Vom desfășura un contract privat pentru participanți Supermarketul și vendor prin intermediul participantului Supermarketul:
const contractAddress = await deployContract( raft1Node, process.env.PK2, ); console.log(`Contract address after deployment: ${contractAddress}`);Setăm temperatura de la terța parte (nod extern) și obținem valoarea temperaturii:
// 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}`);Setăm temperatura de la vendor (nod intern) și obținem valoarea temperaturii:
Temperatura în acest scenariu ar trebui să returneze din smart contract valoarea 12. Observați că vendor aici are acces permis la 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}`);Obținem temperatura de la terța parte (nod extern):
În pasul 3, temperatura a fost setată la 12, dar O terță parte nu are acces la smart contract. Prin urmare, valoarea returnată ar trebui să fie null.
// This returns null const temp3 = await getTemperature(raft3Node, contractAddress); console.log(`[Node3] temp retrieved from external nodes after update ${temp}`);Apoi, să analizăm mai detaliat executarea tranzacțiilor private în rețeaua Quorum cu . Deoarece cea mai mare parte a codului coincide cu tranzacțiile publice, să evidențiem doar acele părți care diferă pentru tranzacții private.
Vă rugăm să rețineți că contractul încărcat în rețea este immutable, astfel încât accesul cu permisiune trebuie acordat nodurilor corespunzătoare prin includerea contractului public în timpul desfășurării contractului, nu după aceea.
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;
});
}În mod similar, tranzacțiile private sunt efectuate prin includerea cheii publice a participanților în momentul desfășurării.
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;
});
}Acum putem să demarăm cu următoarele rezultate:
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 nullExplorerul Quorum în Chainstack va arăta următoarele:
- desfășurarea contractului de către participant Supermarketul;
- Execuție
SetTemperaturede la terța parte; - Execuție
SetTemperaturede către participant vendor.

După cum vedeți, ambele tranzacții au fost efectuate, dar doar tranzacția de la participant vendor a actualizat temperatura în contract. Astfel, tranzacțiile private asigură imutabilitatea, dar în același timp nu dezvăluie datele unei terțe părți.
Concluzie
Am discutat despre un scenariu comercial de utilizare a Quorum pentru a asigura informații actualizate despre temperatura în depozit prin desfășurarea unei rețele între două părți — supermarketul și proprietarul depozitului.
Am arătat cum informațiile actualizate despre temperatură pot fi menținute atât prin tranzacții publice, cât și prin tranzacții private.
Există foarte multe scenarii de aplicare și, după cum puteți vedea, nu este deloc complicat.
Experimentați, încercați să desfășurați propriul vostru scenariu. Mai ales că industria tehnologiilor blockchain .
Sursa: habr.com
