
— blockchain basato su Ethereum, sviluppato da JPMorgan e di recente diventato la prima piattaforma di registro decentralizzato offerta da Microsoft Azure.
Quorum supporta transazioni private e pubbliche e ha numerosi scenari commerciali di utilizzo.
In questo articolo esploreremo uno di questi scenari: l'implementazione di una rete di registro decentralizzato tra un supermercato e un proprietario di magazzino per garantire informazioni aggiornate sulla temperatura del magazzino.
Il codice utilizzato in questo tutorial si trova in .
L'articolo copre:
- creazione di un contratto intelligente;
- implementazione della rete Quorum tramite ;
- transazioni pubbliche Quorum;
- transazioni private Quorum.
Per illustrare viene utilizzato uno scenario di monitoraggio della temperatura nei magazzini dei membri della rete Quorum nell'ambito dell'Internet delle Cose (IoT).
Contesto
Un gruppo di aziende di magazzino si unisce in un consorzio per condividere informazioni e automatizzare processi sulla blockchain. Per questo, le aziende hanno deciso di utilizzare Quorum. In questo articolo copriremo due scenari: transazioni pubbliche e transazioni private.
Le transazioni vengono create da diversi partecipanti per interagire con il consorzio a cui appartengono. Ogni transazione deploya un contratto o chiama una funzione nel contratto per caricare dati nella rete. Queste azioni vengono replicate su tutti i nodi nella rete.
Le transazioni pubbliche sono visibili a tutti i membri del consorzio. Le transazioni private, invece, aggiungono un livello di riservatezza e sono accessibili solo a quei membri che hanno i diritti per farlo.
Per entrambi gli scenari utilizzeremo lo stesso contratto per chiarezza.
Smart contract
Di seguito è riportato un semplice contratto intelligente creato per il nostro scenario. Esso contiene una variabile pubblica temperature, che può essere modificata mediante il metodo set e recuperata tramite il metodo 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;
}
}Affinché il contratto funzioni con , deve essere convertito nel formato ABI e bytecode. L'uso della funzione formatContract, riportata di seguito, compila il contratto utilizzando .
function formatContract() {
const path = '.\/contracts\/temperatureMonitor.sol';
const source = fs.readFileSync(path,'UTF8');
return solc.compile(source, 1).contracts[':TemperatureMonitor'];
}Il contratto finale appare come segue:
// 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
0x608060405234801561001057600080fd5b50610104806100206000396000f30060806040526004361060525763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416636d4ce63c81146057578063adccea12146082578063faee13b9146094575b600080fd5b348015606257600080fd5b50606960ae565b60408051600092830b90920b8252519081900360200190f35b348015608d57600080fd5b50606960b7565b348015609f57600080fd5b5060ac60043560000b60c0565b005b60008054900b90565b60008054900b81565b6000805491810b60ff1660ff199092169190911790555600a165627a7a72305820af0086d55a9a4e6d52cb6b3967afd764ca89df91b2f42d7bf3b30098d222e5c50029Ora che il contratto è pronto, procederemo con il deployment della rete e il deploy del contratto.
Distribuzione dei nodi

Il deployment del nodo può essere piuttosto laborioso e questo processo può essere sostituito utilizzando un servizio .
Di seguito è riportato il processo di deployment della rete Quorum con consenso Raft e tre nodi.
Per iniziare, creiamo un progetto e lo chiamiamo Quorum Project:

Creiamo una rete Quorum con consenso Raft su Google Cloud Platform:

Aggiungeremo due nodi a quello già creato di default:

Tre nodi avviati:

La pagina dei dettagli del nodo mostra l'endpoint RPC, la chiave pubblica, ecc.

La rete è stata distribuita. Ora ci occuperemo del deployment dei contratti intelligenti e dell'esecuzione delle transazioni tramite .
Transazioni pubbliche
Contesto
La temperatura del magazzino è molto importante per ridurre i costi, soprattutto per i prodotti destinati a essere conservati a basse temperature.
Consentendo alle aziende di condividere i valori della temperatura esterna della loro posizione geografica in tempo reale e di registrarli in un registro immutabile, i partecipanti alla rete riducono costi e tempi.

Svolgeremo tre compiti, illustrati nel diagramma:
Deployiamo il contratto tramite Nodo 1:
const contractAddress = await deployContract(raft1Node); console.log(`Indirizzo del contratto dopo il deployment: ${contractAddress}`);Imposteremo la temperatura tramite Nodo 2 a 3 gradi:
const status = await setTemperature(raft2Node, contractAddress, 3); console.log(`Stato della transazione: ${status}`);Nodo 3 recupererà informazioni dal contratto intelligente. Il contratto restituirà il valore di 3 gradi:
const temp = await getTemperature(raft3Node, contractAddress); console.log('Temperatura del contratto recuperata', temp);Vediamo ora come eseguire una transazione pubblica nella rete Quorum utilizzando .
Iniziamo l'istanza tramite RPC per tre nodi:
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,
},
);Deployiamo un contratto intelligente:
// 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;
});
} fornisce due metodi per interagire con il contratto: call e send.
Aggiorniamo la temperatura del contratto eseguendo set utilizzando il metodo 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;
});
}Usiamo poi il metodo web3 call per ottenere la temperatura del contratto. Si prega di notare che il metodo call viene eseguito su un nodo locale e nel blockchain non verrà creata alcuna transazione.
// 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);
}Ora possiamo avviare per ottenere il seguente risultato:
// Execute public script
node public.js
Contract address after deployment: 0xf46141Ac7D6D6E986eFb2321756b5d1e8a25008F
Transaction status: true
Retrieved contract Temperature 3In seguito possiamo visualizzare le registrazioni nell'esploratore Quorum nel pannello Chainstack, come mostrato di seguito.
Tutti e tre i nodi hanno interagito e le transazioni sono state aggiornate:
- La prima transazione ha distribuito il contratto.
- La seconda transazione ha impostato la temperatura del contratto a 3 gradi.
- Il recupero della temperatura avviene tramite il nodo locale, quindi non è stata creata alcuna transazione.

Transazioni private
Contesto
Una necessità comune per le organizzazioni è la protezione dei dati. Consideriamo come esempio uno scenario in cui un supermercato affitta uno spazio di magazzino per la conservazione dei frutti di mare da un fornitore:
- Fornitore utilizzando sensori IoT per registrare i valori di temperatura ogni 30 secondi e trasferirli al supermercato.;
- Questi valori devono essere accessibili solo al fornitore. e Supermercato, uniti in una rete consortile.

Completeremo quattro compiti illustrati nel diagramma sopra.
- Utilizzeremo gli stessi tre nodi dello scenario precedente per dimostrare le transazioni private:
- Il supermercato distribuisce un contratto intelligente che è privato per il supermercato. e fornitore.
- Una terza parte non ha diritto di accesso al contratto intelligente.
Inviteremo i metodi get e set per conto di il supermercato. e fornitore per dimostrare una transazione privata di Quorum.
Distribuiremo un contratto privato per i partecipanti Il supermercato e Fornitore tramite il partecipante Il supermercato:
const contractAddress = await deployContract( raft1Node, process.env.PK2, ); console.log(`Indirizzo del contratto dopo la distribuzione: ${contractAddress}`);Imposteremo la temperatura da una terza parte (nodo esterno) e otterremo il valore della temperatura:
// 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}`);Imposteremo la temperatura da fornitore (nodo interno) e otterremo il valore della temperatura:
In questo scenario, la temperatura dovrebbe restituire dal contratto intelligente un valore di 12. Si prega di notare che Fornitore qui ha accesso autorizzato al contratto intelligente.
// 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}`);Otterremo la temperatura da una terza parte (nodo esterno):
Al passo 3, la temperatura è stata impostata a 12, ma Una terza parte non ha accesso al contratto intelligente. Pertanto, il valore di ritorno dovrebbe essere null.
// This returns null const temp3 = await getTemperature(raft3Node, contractAddress); console.log(`[Node3] temp retrieved from external nodes after update ${temp}`);Passiamo ora a esaminare più in dettaglio l'esecuzione delle transazioni private nella rete Quorum con . Poiché gran parte del codice è simile alle transazioni pubbliche, evidenziamo solo le parti che differiscono per le transazioni private.
Si prega di notare che il contratto caricato sulla rete è immutabile, quindi l'accesso con autorizzazione (permissioned) deve essere concesso ai nodi appropriati includendo il contratto pubblico al momento del deployment del contratto, e non dopo.
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’,
\/\/ Concedi Permesso al Contratto includendo le chiavi pubbliche dei nodi
privateFor: [publicKey],
})
.then((contract) => {
return contract.options.address;
});
}Allo stesso modo vengono eseguite le transazioni private, includendo la chiave pubblica dei partecipanti al momento dell'esecuzione.
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,
\/\/ Concedi Permesso includendo le chiavi pubbliche dei nodi
privateFor: [publicKey],
}).then((receipt) => {
return receipt.status;
});
}Ora possiamo iniziare con i seguenti risultati:
node private.js
Indirizzo contratto dopo il deployment: 0x85dBF88B4dfa47e73608b33454E4e3BA2812B21D
[Node3] temperatura recuperata dopo l'aggiornamento del contratto dai nodi esterni: null
[Node2] temperatura recuperata dopo l'aggiornamento del contratto dai nodi interni: 12
[Node3] temperatura recuperata dai nodi esterni dopo l'aggiornamento nullL'esplora Quorum in Chainstack mostrerà quanto segue:
- deploy del contratto da parte di un partecipante Il supermercato;
- Esecuzione
SetTemperaturedi una terza parte; - Esecuzione
SetTemperatureda un partecipante Fornitore.

Come potete vedere, entrambe le transazioni sono state eseguite, ma solo la transazione da parte del partecipante Fornitore ha aggiornato la temperatura nel contratto. Pertanto, le transazioni private garantiscono l'immutabilità, ma non rivelano i dati a terzi.
Conclusione
Abbiamo esaminato uno scenario commerciale per l'uso di Quorum al fine di garantire informazioni aggiornate sulla temperatura nel magazzino, creando una rete tra due parti: il supermercato e il proprietario del magazzino.
Abbiamo dimostrato come le informazioni attuali sulla temperatura possono essere mantenute sia attraverso transazioni pubbliche che private.
Ci possono essere molti scenari di applicazione e, come vedete, non è poi così difficile.
Sperimentate, provate a implementare il vostro scenario. Inoltre, l'industria delle tecnologie blockchain .
Fonte: habr.com
