WEB3DEV Español

Delia Viloria T
Delia Viloria T

Posted on

Cargar archivos comprimidos a un contrato inteligente de Solidity

Image description

La innovación está llamando

Al utilizar el nuevo e increíble Chat GPT de open AI, una cabeza llena ideas y el conocimiento para unir todo esto, logré producir esta guía en tiempo record.

Si tú todavía no lo has comprobado, diviértete aquí.

Crea una aplicación React

Esta guía asume que tienes un nodo configurado. Si no lo tienes, puedes instalarlo aquí.

Crea un nuevo directorio para nuestra aplicación frontend en tu escritorio, abre una nueva ventana de terminal y haz un cd (change directory o cambiar directorio) para ese directorio.

Una vez en este nuevo directorio, escribe lo siguiente en el terminal para crear una nueva aplicación de React:

npx create-react-app FileCompressor
Enter fullscreen mode Exit fullscreen mode

Una vez instalada, se construirá tu nueva estructura de directorio.

Añade un formulario de carga de frontend

Ve a src/app.js y navega en la función App para introducir esta lógica:

import React from "react";

function App(props) {
 const handleChange = e => {
   const fileReader = new FileReader();
   fileReader.readAsText(e.target.files[0], "UTF-8");
   fileReader.onload = e => {
     if(e.target !== null) {
       console.log("e.target.result", e.target.result);
     }
   };
 };

 return (
   <>
     <h1>Upload file</h1>

     <input type="file" onChange={handleChange} />
   </>
 );
}


Enter fullscreen mode Exit fullscreen mode

Esto creará una nueva función llamada handleChange que se llama cada vez que se carga un archivo en el frontend.

Base64

Nuestros archivos actualmente no tienen un formato que la cadena pueda entender. Entonces necesitamos convertirlos en una cadena Base64 que pueda ser almacenada en la cadena.

Regresa a tu archivo app.js donde agregaremos la lógica Base64 al método handleChange:

import React from "react";

function App(props) {
 const handleChange = e => {
   const fileReader = new FileReader();
   fileReader.readAsDataURL(file)
   fileReader.onload = () => {
     console.log(fileReader.result);
   }
   fileReader.onerror = (error) => {
     console.log(error);
   }
 };

 return (
   <>
     <h1>Upload file</h1>

     <input type="file" onChange={handleChange} />
   </>
 );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Hasta ahora, tenemos un formulario de carga de archivo que toma la entrada, convierte el archivo para un string de base64 y consola.logs la salida (imprime en la consola como un mensaje de registro). Por lo tanto, esto es bueno pero, es mucho mejor usar la compresión para reducir el número de bytes.

Compresión de String LZ

Primero instala la biblioteca para compresión lz:

npm i lzma-js
Enter fullscreen mode Exit fullscreen mode

Una vez instalado, modifica el app.js para que se parezca al siguiente ejemplo, esto registrará el string de base64 comprimida en el terminal:

import React from "react";
import LZMA from "lzma-js";

function App(props) {
 const handleChange = e => {
   const fileReader = new FileReader();
   fileReader.readAsDataURL(file)
   fileReader.onload = () => {
     // Converter o string codificado de base64 em um Uint8Array
     const uint8Array = Uint8Array.from(atob(fileReader.result), c => c.charCodeAt(0));


     // Compactar o Uint8Array usando LZMA-JS
     LZMA.compress(uint8Array, 9, (result, error) => {
       if (error) {
         // Tratar o erro
       } else {
         // Os dados compactados são um Uint8Array, então você precisa convertê-los para um string codificado de base64
         const compressedBase64String = btoa(String.fromCharCode(...result));
         console.log(compressedBase64String); // Outputs the compressed base64 encoded string
       }
     });
   }
   fileReader.onerror = (error) => {
     console.log(error);
   }
 };

 return (
   <>
     <h1>Upload file</h1>

     <input type="file" onChange={handleChange} />
   </>
 );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

El contrato inteligente

Este es un contrato inteligente simple que almacena un conjunto de strings de 32 bytes. En este caso, nuestros 32 bytes son archivos.

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

contract FileStorage {
 mapping (address => bytes32[]) userFiles;

 function addFile(string calldata _file) public {
   userFiles[msg.sender].push(_file);
 }

 function deleteFile(uint arrayIndex) public {
   delete userFiles[msg.sender][arrayIndex];
 }

 function getFiles() public view returns (bytes32[] memory) {
   return userFiles[msg.sender];
 }
}
Enter fullscreen mode Exit fullscreen mode

Esto es lo mínimo necesario. Para los casos de producción, probablemente necesitarías mucho más pero, el contrato de arriba será suficiente para el propósito de este tutorial. Una vez implementado, estarás listo para conectar tu aplicación React a su base de datos de archivos descentralizada.

Conectando el Dapp

Primero, toma la abi (interfaz binaria de la aplicación) para tu contrato de implementación y guárdala en un nuevo archivo llamado abi.json.

[
{
 "inputs": [
  {
   "internalType": "string",
   "name": "_file",
   "type": "string"
  }
 ],
 "name": "addFile",
 "outputs": [],
 "stateMutability": "nonpayable",
 "type": "function"
},
{
 "inputs": [
  {
   "internalType": "uint256",
   "name": "arrayIndex",
   "type": "uint256"
  }
 ],
 "name": "deleteFile",
 "outputs": [],
 "stateMutability": "nonpayable",
 "type": "function"
},
{
 "inputs": [],
 "name": "getFiles",
 "outputs": [
  {
   "internalType": "string[]",
   "name": "",
   "type": "string[]"
  }
 ],
 "stateMutability": "view",
 "type": "function"
}
]
Enter fullscreen mode Exit fullscreen mode

Si regresas al archivo app.js, la etapa final será reemplazar nuestro registro de la consola del string de los archivos por una llamada de contrato inteligente. Primero, ingresamos el contrato abi, completamos la dirección del contrato, nos conectamos a MetaMask a través del frontend y luego permitimos que el archivo de los usuarios sea almacenado después de que se haya establecido la conexión.

import React from "react";
import LZMA from "lzma-js";

function App(props) {
 const abi = require('./abi.json');
 const handleChange = e => {
   const fileReader = new FileReader();
   const CONTRACT_ADDRESS = "0xof";
   fileReader.readAsDataURL(file)
   fileReader.onload = () => {
     // Converter o string de base64 codificado em um Uint8Array
     const uint8Array = Uint8Array.from(atob(fileReader.result), c => c.charCodeAt(0));


     // Compactar o  Uint8Array using LZMA-JS
     LZMA.compress(uint8Array, 9, (result, error) => {
       if (error) {
         console.log(error);
       } else {
           // Os dados compactados são Uint8Array, então você precisa convertê-los para um string de base64 codificado
           const compressedBase64String = btoa(String.fromCharCode(...result));
           const { ethereum } = window;
           const provider = new ethers.providers.Web3Provider(ethereum);
           const signer = provider.getSigner()
           const connectedContract = new ethers.Contract(CONTRACT_ADDRESS, abi, signer);

           let tx = async() => await connectedContract.addFile(compressedBase64String);

           console.log(tx); // Emitir o resultado da chamada do contrato inteligente
       }
     });
   }
   fileReader.onerror = (error) => {
     console.log(error);
   }
 };

 return (
   <>
     <h1>Upload file</h1>

     <input type="file" onChange={handleChange} />
   </>
 );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Esto es todo lo que necesitas para comprimir documentos de palabras y almacenarlos en cadena, no solo documentos de palabras, sino prácticamente cualquier tipo de archivo que pueda entender el cargador basado en el navegador.

Para recuperar tus archivos y descomprimirlos necesitarás crear un nuevo método para consultar la función getFiles y revisar los contratos inteligentes a través de cada uno de ellos. Dentro de cada iteración, simplemente llamarías el método que verás abajo y almacenas los datos descomprimidos de cualquier forma que se adapte a tu caso de uso:

LZMA.decompress(properties, inStream, outStream, outSize);
Enter fullscreen mode Exit fullscreen mode

Hay tantas posibilidades para este enfoque pero, como siempre, esta es solo una guía para llevarte a una base de comprensión sólida, pero de ninguna manera está lista para la producción.

¡Estás listo para crear!

Este artículo fue escrito por Robert McMenemy y traducido por Delia Viloria T. El original puede ser leído aquí.

Sería genial encontrarnos en nuestro Discord, puedes contarnos tus ideas, comentarios, sugerencias y dejarnos saber lo que necesitas.
Si prefieres puedes escribirnos a @web3dev_es en Twitter.

Discussion (1)

Collapse
junowoz profile image
Juan José Gouvêa

nice