
— una blockchain basata su Ethereum, sviluppata da JPMorgan e recentemente diventata la prima piattaforma di registro distribuito offerta da Microsoft Azure.
Quorum supporta transazioni private e pubbliche e presenta numerosi scenari commerciali applicabili.
In questo articolo esploreremo uno di questi scenari: il deployment di una rete di registro distribuito 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 uno smart contract;
- deployment della rete Quorum tramite ;
- transazioni pubbliche di Quorum;
- transazioni private di Quorum.
Per illustrare viene utilizzato uno scenario di monitoraggio della temperatura negli ambienti di magazzino dei partecipanti alla rete Quorum nell'ambito dell'Internet of Things (IoT).
Contesto
Un gruppo di aziende di magazzini si unisce in un consorzio per condividere informazioni e automatizzare processi sulla blockchain. Per questo motivo, le aziende hanno deciso di utilizzare Quorum. In questo articolo tratteremo due scenari: transazioni pubbliche e transazioni private.
Le transazioni sono create da diversi partecipanti per interagire con il consorzio a cui appartengono. Ogni transazione distribuisce un contratto o richiama una funzione nel contratto per caricare dati sulla rete. Queste azioni vengono replicate su tutti i nodi della 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 ne hanno il diritto.
Per entrambi gli scenari utilizziamo, per chiarezza, lo stesso contratto.
Smart contract
Di seguito è riportato un semplice smart contract, creato per il nostro scenario. Contiene una variabile pubblica temperature, che può essere modificata tramite 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;
}
}Per far funzionare il contratto con , deve essere convertito nel formato ABI e bytecode. L'uso della funzione formatContract, illustrata 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 pronto 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 alla distribuzione della rete e al deployment del contratto.
Distribuzione dei nodi

Distribuire un nodo può essere piuttosto impegnativo e questo processo può essere sostituito con l'uso di un servizio. .
Di seguito è riportato il processo per la distribuzione di una rete Quorum con consenso Raft e tre nodi.
Per iniziare, creiamo un progetto e chiamiamolo Quorum Project:

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

Aggiungeremo due nodi a quello già creato di default:

Tre nodi in esecuzione:

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

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

Affronteremo tre compiti illustrati nel diagramma:
Deployeremo 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 riceverà informazioni dal contratto intelligente. Il contratto restituirà il valore di 3 gradi:
const temp = await getTemperature(raft3Node, contractAddress); console.log('Temperatura recuperata dal contratto', temp);Successivamente, vedremo come eseguire una transazione pubblica nella rete Quorum utilizzando .
Iniziamo un'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,
},
);Deployeremo il 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.
Aggiorneremo 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;
});
}Successivamente, utilizziamo il metodo web3 call per recuperare la temperatura del contratto. Si noti che il metodo call viene eseguito su un nodo locale e non verrà creata alcuna transazione sulla 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);
}Ora possiamo avviare per ottenere il risultato successivo:
// Execute public script
node public.js
Contract address after deployment: 0xf46141Ac7D6D6E986eFb2321756b5d1e8a25008F
Transaction status: true
Retrieved contract Temperature 3Dopo, 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 deployato il contratto.
- La seconda transazione ha impostato la temperatura del contratto a 3 gradi.
- Il recupero della temperatura avviene tramite un nodo locale, quindi non è stata creata alcuna transazione.

Transazioni private
Contesto
Una richiesta comune delle organizzazioni è la protezione dei dati. Come esempio, consideriamo uno scenario in cui Un supermercato affitta un magazzino per lo stoccaggio dei frutti di mare da un Fornitore:
- Fornitore utilizza sensori IoT per registrare i valori di temperatura ogni 30 secondi e li trasmette al supermercato;
- questi valori devono essere accessibili solo al Fornitore e Supermercato, uniti in una rete consorziale.

Espleteremo quattro compiti, illustrati nel diagramma sopra.
- Utilizziamo le stesse tre nodi dello scenario precedente per dimostrare le transazioni private:
- Supermercato deploiterà un contratto intelligente che è privato per Il supermercato e Fornitore.
- Una terza parte non ha accesso al contratto intelligente.
Invocheremo i metodi get e set per conto di Il supermercato e Fornitore per dimostrare la transazione privata di Quorum.
Deploiteremo un contratto privato per i partecipanti Supermercato e Fornitore attraverso il partecipante Supermercato:
const contractAddress = await deployContract( raft1Node, process.env.PK2, ); console.log(`Indirizzo del contratto dopo il deployment: ${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:
La temperatura in questo scenario dovrebbe restituire dal contratto intelligente il valore 12. Si noti 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}`);Ottenere la temperatura da Una terza parte (nodo esterno):
Nel passo 3 la temperatura è stata impostata con un valore di 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}`);Successivamente, esamineremo più nel dettaglio l'esecuzione di transazioni private nella rete Quorum con . Poiché gran parte del codice coincide con le transazioni pubbliche, evidenziamo solo le parti che differiscono per le transazioni private.
Si noti che il contratto caricato nella rete è immutabile, quindi l'accesso con permesso deve essere fornito ai nodi interessati inclusi nel contratto pubblico al momento del deployment, 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',
// Grant Permission to Contract by including nodes public keys
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,
// Grant Permission by including nodes public keys
privateFor: [publicKey],
}).then((receipt) => {
return receipt.status;
});
}Ora possiamo avviare con i seguenti risultati:
node private.js
Indirizzo del contratto dopo il deploy: 0x85dBF88B4dfa47e73608b33454E4e3BA2812B21D
[Node3] temperatura recuperata dopo l'aggiornamento del contratto da nodi esterni: null
[Node2] temperatura recuperata dopo l'aggiornamento del contratto da nodi interni: 12
[Node3] temperatura recuperata da nodi esterni dopo l'aggiornamento nullL'Explorer Quorum in Chainstack mostrerà quanto segue:
- deploy del contratto da parte di un partecipante Supermercato;
- Esecuzione
SetTemperatureda Una terza parte; - Esecuzione
SetTemperatureda un partecipante Fornitore.

Come potete vedere, entrambe le transazioni sono state completate, ma solo la transazione da parte del partecipante Fornitore ha aggiornato la temperatura nel contratto. Pertanto, le transazioni private garantiscono l'immutabilità, ma non forniscono dati di terze parti.
Conclusione
Abbiamo esaminato uno scenario commerciale che utilizza Quorum per garantire informazioni aggiornate sulla temperatura in un magazzino, implementando una rete tra due parti: il supermercato e il proprietario del magazzino.
Abbiamo dimostrato come le informazioni aggiornate sulla temperatura possano essere mantenute sia attraverso transazioni pubbliche che private.
Le possibilità di applicazione possono essere molteplici e, come vedete, non è per nulla complicato.
Sperimentate, provate a implementare il vostro scenario. Inoltre, l'industria della tecnologia blockchain .
Fonte: habr.com
