Executarea tranzacțiilor publice și private în blockchain-ul JPMorgan Quorum utilizând Web3

Executarea tranzacțiilor publice și private în blockchain-ul JPMorgan Quorum utilizând Web3

Quorum — 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 repositorii pe GitHub.

Articolul acoperă:

  • crearea unui smart contract;
  • desfășurarea rețelei Quorum folosind Chainstack;
  • 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 web3.jsformatContract , 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']; }.

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
0x608060405234801561001057600080fd5b50610104806100206000396000f30060806040526004361060525763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416636d4ce63c81146057578063adccea12146082578063faee13b9146094575b600080fd5b348015606257600080fd5b50606960ae565b60408051600092830b90920b8252519081900360200190f35b348015608d57600080fd5b50606960b7565b348015609f57600080fd5b5060ac60043560000b60c0565b005b60008054900b90565b60008054900b81565b6000805491810b60ff1660ff199092169190911790555600a165627a7a72305820af0086d55a9a4e6d52cb6b3967afd764ca89df91b2f42d7bf3b30098d222e5c50029

Acum că contractul este pregătit, vom desfășura rețeaua și vom implementa contractul.

Implementarea nodurilor

Executarea tranzacțiilor publice și private în blockchain-ul JPMorgan Quorum utilizând Web3

Desfășurarea nodului poate fi destul de laborioasă și acest proces poate fi înlocuit prin utilizarea unui serviciu. Chainstack.

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:

Executarea tranzacțiilor publice și private în blockchain-ul JPMorgan Quorum utilizând Web3

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

Executarea tranzacțiilor publice și private în blockchain-ul JPMorgan Quorum utilizând Web3

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

Executarea tranzacțiilor publice și private în blockchain-ul JPMorgan Quorum utilizând Web3

Cele trei noduri active:

Executarea tranzacțiilor publice și private în blockchain-ul JPMorgan Quorum utilizând Web3

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

Executarea tranzacțiilor publice și private în blockchain-ul JPMorgan Quorum utilizând Web3

Rețeaua este desfășurată. Acum să ne ocupăm de implementarea smart contractelor și efectuarea tranzacțiilor prin web3.js.

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.

Executarea tranzacțiilor publice și private în blockchain-ul JPMorgan Quorum utilizând Web3

Vom îndeplini trei sarcini, ilustate în diagrama:

  1. Vom implementa contractul prin Nodul 1:

    const contractAddress = await deployContract(raft1Node);
    console.log(`Adresa contractului după desfășurare: ${contractAddress}`);

  2. Să setăm temperatura prin Nodul 2 la 3 grade:

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

  3. 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 web3.js.

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

web3.js 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 public.js pentru a obține următorul rezultat:

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

Apoi, 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:

  1. Prima tranzacție a desfășurat contractul.
  2. A doua tranzacție a setat temperatura contractului la 3 grade.
  3. Obținerea temperaturii se face prin nodul local, deci tranzacția nu a fost creată.

Executarea tranzacțiilor publice și private în blockchain-ul JPMorgan Quorum utilizând Web3

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.

Executarea tranzacțiilor publice și private în blockchain-ul JPMorgan Quorum utilizând Web3

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.

  1. 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}`);

  2. 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}`);

  3. 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}`);

  4. 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 web3.js. 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 private.js 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 null

Explorerul Quorum în Chainstack va arăta următoarele:

  • desfășurarea contractului de către participant Supermarketul;
  • Execuție SetTemperature de la terța parte;
  • Execuție SetTemperature de către participant vendor.

Executarea tranzacțiilor publice și private în blockchain-ul JPMorgan Quorum utilizând Web3

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 ar putea crește aproape de zece ori până în 2024.

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster