Realización de transacciones públicas y privadas en la cadena de bloques JPMorgan Quorum usando Web3



Quorum es una cadena de bloques basada en Ethereum desarrollada por JPMorgan y recientemente se convirtió en la primera plataforma de registro distribuida que ofrece Microsoft Azure.


Quorum admite transacciones privadas y públicas y tiene muchos casos de uso comercial.


En este artículo, analizaremos uno de estos escenarios: el despliegue de una red de registro distribuido entre un supermercado y el propietario de un almacén para proporcionar información relevante sobre la temperatura de un almacén.


El código utilizado en esta guía se encuentra en el repositorio en GitHub .


El artículo cubre:


  • creando un contrato inteligente;
  • Implementación de la red de quórum con Chainstack
  • Transacciones públicas de quórum
  • Quórum de transacciones privadas.

Para ilustrar esto, utilizamos el escenario de monitoreo de temperatura en los cuartos de almacenamiento de los participantes de la red del Quórum como parte de Internet de las Cosas (IoT).


Contexto


Un grupo de empresas de almacén está unido en un consorcio para el almacenamiento conjunto de información y la automatización de procesos en la cadena de bloques. Para esto, las compañías decidieron usar Quorum. En este artículo, cubriremos dos escenarios: transacciones públicas y transacciones privadas.


Los diferentes participantes crean transacciones para interactuar con el consorcio al que pertenecen. Cada transacción despliega un contrato o llama a una función en un contrato para cargar datos a la red. Estas acciones se replican en todos los nodos de la red.


Las transacciones públicas están disponibles para que todos los miembros del consorcio las vean. Las transacciones privadas agregan una capa de confidencialidad y están disponibles solo para aquellos participantes que tienen derechos sobre ellas.


Para ambos escenarios, utilizamos el mismo contrato para mayor claridad.


Contrato inteligente


A continuación se muestra un contrato inteligente simple creado para nuestro escenario. Tiene una temperature pública variable, que se puede cambiar usando el método set y recuperar con el método 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; } } 

Para que el contrato funcione con web3.js , debe convertirse a formato ABI y bytecode. Usando la función formatContract continuación compila el contrato usando solc-js .


 function formatContract() { const path = './contracts/temperatureMonitor.sol'; const source = fs.readFileSync(path,'UTF8'); return solc.compile(source, 1).contracts[':TemperatureMonitor']; } 

El contrato terminado es el siguiente:


 // 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 

Ahora que el contrato está listo, implementaremos la red e implementaremos el contrato.


Despliegue de nodos


imagen


La implementación de un nodo puede llevar mucho tiempo y este proceso se puede reemplazar con el servicio Chainstack .


El siguiente es un proceso de implementación de red de quórum con consenso de Raft y tres nodos.


Para comenzar, comencemos un proyecto y llamémoslo Proyecto Quórum:


imagen


Cree una red de quórum con el consenso de Raft en Google Cloud Platform:


imagen


Al nodo predeterminado ya creado, agregue dos nodos más:


imagen


Tres nodos en ejecución:


imagen


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


imagen


La red está desplegada. Ahora vamos a implementar contratos inteligentes y ejecutar transacciones usando web3.js.


Transacciones públicas


Contexto


La temperatura del almacén es de gran importancia para reducir costos, especialmente para productos destinados al almacenamiento a temperaturas bajo cero.


Al dar a las empresas la capacidad de compartir valores en tiempo real de la temperatura externa de su ubicación geográfica y registrarlos en un registro inmutable, los miembros de la red reducen los costos y el tiempo.


imagen


Completaremos las tres tareas ilustradas en el diagrama:


  1. Terminaremos el contrato a través del Nodo 1 :


     const contractAddress = await deployContract(raft1Node); console.log(`Contract address after deployment: ${contractAddress}`); 

  2. Ajuste la temperatura a través del nodo 2 a 3 grados:


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

  3. El nodo 3 recibirá información del contrato inteligente. El contrato devolverá un valor de 3 grados:


     const temp = await getTemperature(raft3Node, contractAddress); console.log('Retrieved contract Temperature', temp); 

    A continuación, veremos cómo ejecutar una transacción pública en la red de Quorum usando web3.js.



Iniciamos una instancia a través de RPC para 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, }, ); 

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

web3.js proporciona dos métodos para interactuar con un contrato: call y send .


Actualice la temperatura del contrato ejecutando set usando el método de send web3.


 // 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, utilizamos el método de call web3 para obtener la temperatura del contrato. Tenga en cuenta que el método de call se ejecuta en el nodo local y la transacción no se creará en la cadena de bloques.


 // 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 puede ejecutar public.js para obtener el siguiente resultado:


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

A continuación, podemos ver las entradas en el explorador de quórum en el panel Chainstack, como se muestra a continuación.


Los tres nodos interactuaron y las transacciones se actualizaron:


  1. La primera transacción ha asegurado un contrato.
  2. La segunda transacción estableció la temperatura del contrato en 3 grados.
  3. La temperatura se obtiene a través del nodo local, por lo que la transacción no se ha creado.

imagen


Transacciones privadas


Contexto


Un requisito común de las organizaciones es la protección de datos. Como ejemplo, considere un escenario en el que un supermercado alquila un almacén para almacenar mariscos de un proveedor separado:


  • El vendedor con la ayuda de sensores IoT lee los valores de temperatura cada 30 segundos y los pasa al Supermercado ;
  • estos valores deberían estar disponibles solo para el Vendedor y el Supermercado , un consorcio en red.

imagen


Completaremos las cuatro tareas ilustradas en el diagrama anterior.


  • Utilizamos los mismos tres nodos del escenario anterior para demostrar transacciones privadas:
  • El supermercado está implementando un contrato inteligente que es privado para el supermercado y el vendedor .
  • Un tercero no tiene acceso al contrato inteligente.

Llamaremos a los métodos get y set en nombre del Supermercado y el Vendedor para demostrar la transacción privada del Quórum.


  1. Terminaremos el contrato privado para los participantes del Supermercado y el Vendedor a través del participante del Supermercado :


     const contractAddress = await deployContract( raft1Node, process.env.PK2, ); console.log(`Contract address after deployment: ${contractAddress}`); 

  2. Establezca la temperatura del Tercero (nodo externo) y obtenga 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}`); 

  3. Establezca la temperatura desde el proveedor (nodo interno) y obtenga el valor de temperatura:


    La temperatura en este escenario debería volver del contrato inteligente a 12. Tenga en cuenta que el proveedor aquí ha permitido el acceso 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}`); 

  4. Obtenga la temperatura del tercero (nodo externo):


    En el paso 3, la temperatura se estableció en 12, pero el tercero no tiene acceso al contrato inteligente. Por lo tanto, el valor de retorno debe 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, consideraremos con más detalle la ejecución de transacciones privadas en la red de Quorum con web3.js. Como la mayor parte del código coincide con las transacciones públicas, seleccionamos solo aquellas partes que son diferentes para las transacciones privadas.



Tenga en cuenta que el contrato cargado en la red no puede modificarse, por lo tanto, el acceso con permiso debe otorgarse a los nodos correspondientes al incluir el contrato público en el momento del despliegue 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; }); } 

Las transacciones privadas se realizan de la misma manera, incluyendo 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 private.js 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 null 

El explorador del quórum en Chainstack mostrará lo siguiente:


  • Despliegue de un contrato de un participante en un supermercado ;
  • Realizar SetTemperature de un tercero ;
  • Realice un SetTemperature de un proveedor participante.

imagen


Como puede ver, ambas transacciones se completan, pero solo la transacción del proveedor participante actualizó la temperatura en el contrato. Por lo tanto, las transacciones privadas proporcionan inmutabilidad, pero al mismo tiempo no proporcionan datos a un tercero.


Conclusión


Examinamos el escenario comercial para usar Quorum para proporcionar información actualizada de temperatura en un almacén mediante el despliegue de una red entre dos partes: un supermercado y el propietario del almacén.


Hemos mostrado cómo se puede mantener la información de temperatura actual a través de transacciones públicas y privadas.


Puede haber muchos escenarios de aplicación y, como puede ver, esto no es del todo difícil.


Experimente, intente implementar su script. Además, la industria de la tecnología blockchain puede crecer casi diez veces para 2024 .

Source: https://habr.com/ru/post/456368/


All Articles