
— una blockchain basada en Ethereum, desarrollada por JPMorgan y que recientemente se ha convertido en la primera plataforma de libro mayor distribuido disponible en Microsoft Azure.
Quorum admite transacciones públicas y privadas y tiene numerosos escenarios comerciales de uso.
En este artículo, analizaremos uno de esos escenarios: el despliegue de una red de libro mayor distribuido entre un supermercado y un operador de almacén para garantizar información actual sobre la temperatura del almacén.
El código utilizado en esta guía se encuentra en .
Este artículo cubre:
- la creación de un contrato inteligente;
- el despliegue de una red Quorum utilizando ;
- transacciones públicas en Quorum;
- transacciones privadas en Quorum.
Para ilustrar, se utiliza un escenario de monitoreo de temperatura en los almacenes de los participantes de la red Quorum dentro del Internet de las Cosas (IoT).
Contexto
Un grupo de empresas de almacenamiento se une en un consorcio para compartir información y automatizar procesos en la blockchain. Para esto, las empresas decidieron utilizar Quorum. En este artículo cubriremos dos escenarios: transacciones públicas y transacciones privadas.
Las transacciones son creadas por diferentes participantes para interactuar con el consorcio al que pertenecen. Cada transacción despliega un contrato o invoca una función en el contrato para cargar datos en la red. Estas acciones se replican en todos los nodos de la red.
Las transacciones públicas son accesibles para que todos los participantes del consorcio las vean. Las transacciones privadas, en cambio, añaden una capa de confidencialidad y solo son accesibles para aquellos participantes que tienen permisos para ello.
Para ambos escenarios, utilizamos el mismo contrato para mayor claridad.
Contrato inteligente
A continuación, se presenta un contrato inteligente simple creado para nuestro escenario. Tiene una variable pública temperature, que se puede modificar mediante el método 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.
Para que el contrato funcione con, debe ser traducido a formato ABI y bytecode. El uso de la función formatContract , presentada a continuación, compila el contrato utilizandosolc-js .
function formatContract() {
const path = './contracts/temperatureMonitor.sol';
const source = fs.readFileSync(path, 'UTF8');
return solc.compile(source, 1).contracts[':TemperatureMonitor'];
}El contrato listo se ve de la siguiente manera:
// 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
0x608060405234801561001057600080fd5b50610104806100206000396000f30060806040526004361060525763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416636d4ce63c81146057578063adccea12146082578063faee13b9146094575b600080fd5b348015606257600080fd5b50606960ae565b60408051600092830b90920b8252519081900360200190f35b348015608d57600080fd5b50606960b7565b348015609f57600080fd5b5060ac60043560000b60c0565b005b60008054900b90565b60008054900b81565b6000805491810b60ff1660ff199092169190911790555600a165627a7a72305820af0086d55a9a4e6d52cb6b3967afd764ca89df91b2f42d7bf3b30098d222e5c50029Ahora que el contrato está listo, desplegaremos la red y desplegaremos el contrato.
Despliegue de nodos

El despliegue de un nodo puede ser bastante laborioso y este proceso puede ser reemplazado por el uso de un servicio. .
A continuación, se presenta el proceso de despliegue de la red Quorum con consenso Raft y tres nodos.
Primero, crearemos un proyecto y lo nombraremos Proyecto Quorum:

Crearemos una red Quorum con consenso Raft en Google Cloud Platform:

A la ya creada nodo por defecto, añadiremos dos nodos más:

Tres nodos en funcionamiento:

La página de detalles del nodo muestra el punto final RPC, la clave pública, etc.

La red está desplegada. Ahora nos ocuparemos del despliegue de contratos inteligentes y la ejecución de transacciones a través de .
Transacciones públicas
Contexto
La temperatura en el almacén es crucial para reducir costos, especialmente para productos que deben ser almacenados a temperaturas bajo cero.
Al permitir a las empresas compartir valores de temperatura externa de su ubicación geográfica en tiempo real y registrarlos en un libro mayor inmutable, los participantes de la red reducen costos y tiempos.

Realizaremos tres tareas ilustradas en el diagrama:
Desplegaremos el contrato a través de Nodo 1:
const contractAddress = await deployContract(raft1Node); console.log(`Dirección del contrato después del despliegue: ${contractAddress}`);Estableceremos la temperatura a través de Nodo 2 a 3 grados:
const status = await setTemperature(raft2Node, contractAddress, 3); console.log(`Estado de la transacción: ${status}`);Nodo 3 obtendrá información del contrato inteligente. El contrato devolverá el valor de 3 grados:
const temp = await getTemperature(raft3Node, contractAddress); console.log('Temperatura del contrato recuperada', temp);A continuación, veremos cómo ejecutar una transacción pública en la red Quorum utilizando .
Iniciaremos una instancia a través de RPC para los tres nodos:
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,
},
);Desplegaremos el contrato inteligente:
// 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;
});
} proporciona dos métodos para interactuar con el contrato: call y send.
Actualizaremos la temperatura del contrato realizando set utilizando el método 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;
});
}A continuación, utilizaremos el método web3 call para obtener la temperatura del contrato. Tenga en cuenta que el método call se ejecuta en un nodo local y no se generará una transacción en la 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);
}Ahora podemos iniciar para obtener el siguiente resultado:
// Execute public script
node public.js
Contract address after deployment: 0xf46141Ac7D6D6E986eFb2321756b5d1e8a25008F
Transaction status: true
Retrieved contract Temperature 3A continuación, podemos ver los registros en el explorador Quorum en el panel de Chainstack, como se muestra a continuación.
Los tres nodos han interactuado y las transacciones se han actualizado:
- La primera transacción desplegó el contrato.
- La segunda transacción estableció la temperatura del contrato en 3 grados.
- La obtención de la temperatura se realiza a través del nodo local, por lo que no se ha creado una transacción.

Transacciones privadas
Contexto
Un requisito común de las organizaciones es la protección de datos. Tomemos como ejemplo el escenario en el que el supermercado arrienda un espacio de almacenamiento para productos del mar de un Proveedor:
- Proveedor mediante sensores IoT que leen los valores de temperatura cada 30 segundos y los envían al supermercado;
- esos valores deben estar disponibles solo para el proveedor y del supermercado, formando parte de una red de consorcio.

Realizaremos cuatro tareas, ilustradas en el diagrama anterior.
- Usaremos los mismos tres nodos del escenario anterior para demostrar transacciones privadas:
- el supermercado despliega un contrato inteligente que es privado para el supermercado y Proveedor.
- Una tercera parte no tiene acceso al contrato inteligente.
Llamaremos a los métodos get y set en nombre de el supermercado y Proveedor para demostrar una transacción privada en Quorum.
Desplegaremos un contrato privado para los participantes el supermercado y Proveedor a través del participante el supermercado:
const contractAddress = await deployContract( raft1Node, process.env.PK2, ); console.log(`Dirección del contrato después del despliegue: ${contractAddress}`);Estableceremos la temperatura desde la tercera parte (nodo externo) y obtendremos el valor de 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}`);Estableceremos la temperatura desde Proveedor (nodo interno) y obtendremos el valor de temperatura:
La temperatura en este escenario debería devolver el valor 12 desde el contrato inteligente. Tenga en cuenta que Proveedor aquí se tiene acceso permitido al contrato inteligente.
// 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}`);Obtendremos la temperatura desde la tercera parte (nodo externo):
En el paso 3, la temperatura se estableció con un valor de 12, pero Una tercera parte no tiene acceso al contrato inteligente. Por lo tanto, el valor devuelto debería ser nulo.
// This returns null const temp3 = await getTemperature(raft3Node, contractAddress); console.log(`[Node3] temp retrieved from external nodes after update ${temp}`);A continuación, examinaremos más de cerca la ejecución de transacciones privadas en la red Quorum con . Dado que la mayor parte del código coincide con las transacciones públicas, destacaremos solo aquellas partes que difieren para las transacciones privadas.
Tenga en cuenta que el contrato cargado en la red es inmutable, por lo que el acceso con permiso debe ser otorgado a los nodos correspondientes mediante la inclusión del contrato público en el momento de la implementación del contrato, y no después.
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;
});
}De manera similar se realizan transacciones privadas, incluida la clave pública de los participantes en el momento de la ejecución.
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;
});
}Ahora podemos ejecutar con los siguientes resultados:
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 nullEl explorador Quorum en Chainstack mostrará lo siguiente:
- implementación del contrato por parte del participante el supermercado;
- Ejecución
SetTemperaturedesde la tercera parte; - Ejecución
SetTemperaturepor el participante Proveedor.

Como pueden ver, ambas transacciones se ejecutaron, pero solo la transacción del participante Proveedor actualizó la temperatura en el contrato. Por lo tanto, las transacciones privadas garantizan la inmutabilidad, pero no divulgan datos a terceros.
Conclusión
Hemos explorado un escenario comercial que utiliza Quorum para proporcionar información actualizada sobre la temperatura en un almacén a través del despliegue de una red entre dos partes: un supermercado y el propietario del almacén.
Hemos demostrado cómo la información actualizada sobre la temperatura se puede mantener tanto a través de transacciones públicas como privadas.
Los escenarios de aplicación pueden ser muy numerosos y, como pueden ver, no es nada complicado.
Experimente, intente implementar su propio escenario. Más aún, dado que la industria de la tecnología blockchain .
Fuente: habr.com
