Desarrollo de una DApp sobre la red Ethereum

En este tutorial vamos a desarrollar paso a paso una Aplicación Descentralizada (DApp) que permitirá contabilizar los votos a favor, en contra o de abstención de una serie de propuestas, para ello usaremos la Blockchain de Ethereum. El tutorial está orientado a programadores con conocimientos en desarrollo web, pero con poca o nula experiencia en desarrollo de DApps, y nulos conocimientos sobre Ethereum o la tecnología Blockchain en general.

[Imagen[1] (Imagen por gentileza de: https://pixabay.com)]

Probablemente si estás aquí es porque ya hayas escuchado hablar de términos como “Blockchain”, “Smart Contract”, “DApp”, “Ethereum Network”, “Solidity”, etc. Si los términos anteriores te suenan pero nos los tienes del todo claros, te recomiendo que te leas el siguiente artículo antes de continuar con este tutorial.

Para esta primera toma de contacto con el desarrollo de aplicaciones descentralizadas he decidido usar el framework de desarrollo Truffle. Actualmente es el framework más avanzado y usado para estos menesteres por la comunidad. Nos permitirá compilar, desplegar o testear nuestros contratos inteligentes. Está desarrollado en Nodejs y lo usaremos mediante línea de comandos.

Bien, ¿y qué vamos a desarrollar?

Pues una DApp muy sencilla que nos ayude a entender dos de las cualidades más importantes que ofrece la tecnología Blockchain. Nos referimos a la Inmutabilidad y la Transparencia de los datos. Hasta ahora, en las bases de datos transaccionales hablábamos de las operaciones básicas CRUD (Create, Read, Update, Delete). Pero, usando la tecnología Blockchain para almacenar datos el paradigma cambia por completo y las operaciones de modificación y borrado de datos carecen de sentido.

Implementaremos un sistema de votación de propuestas descentralizado. Donde cualquier usuario podrá crear propuestas para que los demás puedan votarlas con las opciones a favor, en contra o abstención. Conviene aclarar que cada usuario podrá ejercer su derecho a voto una sola vez por cada propuesta.

Configuración de las herramientas para el desarrollo:

Ganache

Es una herramienta desarrollada por el equipo de Truffle que nos permitirá ejecutar una Blockchain en local donde podremos desplegar nuestros contratos inteligentes, correr tests e inspeccionar de un modo visual el estado de la blockchain mientras hacemos nuestras operaciones en desarrollo.

Para el desarrollo de aplicaciones descentralizadas sobre Ethereum esta no es la única vía, podríamos también usar alguna de las testnets de Ethereum, pero esto lo dejaremos para tutoriales posteriores.

Para usarlo, podéis descargar el software en su página oficial. Tienen clientes instalables para diferentes sistema operativo.

Una vez descargado, necesitaremos ejecutarlo. En la Imagen 2 podéis comprobar el aspecto del programa.

Ganache en funcionamiento [Imagen[2] (Imagen propia)]

MetaMask

Es una herramienta que nos permitirá interactuar con nuestros contratos inteligentes desde el navegador web.

Para su instalación tan solo necesitáis buscarla como extensión navegadores como Mozilla Firefox o Google Chrome. Recomiendo usar Mozilla Firefox, ya que he experimentado menos problemas.

A continuación, necesitamos configurar MetaMask, para ello recomiendo seguir la detallada guía gráfica de Truffle.

Paso a paso

Lo siguiente que necesitaremos es el código de la DApp. Para esto, lo primero que haremos es abrir nuestra consola y descargamos el proyecto desde Github:

> git clone https://github.com/bukosabino/truffle-voting-dapp.git

A continuación, accedemos al directorio e instalamos los paquetes necesarios para el funcionamiento del proyecto:

> cd truffle-voting-dapp

> npm install

Para compilar nuestro contrato inteligente usaremos el siguiente comando:

> truffle compile

Desplegamos el contrato en nuestra blockchain del siguiente modo:

> truffle migrate — reset

Y por último, podemos ejecutar nuestro servicio con el siguiente comando:

> npm run dev

Ahora puedes ver la aplicación en el navegador que hayas configurado con MetaMask, visitando la url http://localhost:3000.

Puedes crear propuestas y votarlas una única vez por cada usuario a través de tu navegador. Para comprobar esto último puedes cambiar de usuario en MetaMask. Para ello, necesitarás:

  1. Buscar una clave privada de otro usuario en Ganache (pincha en el icono de la llave a la derecha de la Imagen 1, para mostrar la clave privada de cualquier usuario que no sea el primero que aparece ya que es el que MetaMask usa por defecto).
  2. Busca en MetaMask la opción “Import Account” para introducir la clave privada copiada de Ganache.

Explorando el código

Contrato contract/Voting.sol

Si miramos en detalle el código del contrato inteligente, lo primero que podemos apreciar es que para modelar la solución hemos usado 2 structs. Una para las propuestas y otra para los votos.

Te preguntarás por qué en la estructura de las propuestas tenemos a la vez un map que apunta a los votos y una lista de los usuarios que han votado. Esto es así porque solidity no nos permite retornar el map e iterar sobre este para comprobar los usuarios que han votado. Pero sí nos permite esto usando una lista, por tanto, la usaremos aunque suponga una duplicación de la información.

Además de las estructuras para modelar los datos, disponemos de algunas funciones y eventos útiles para comunicar los datos de la Blockchain con el cliente en Javascript.

Solidity no nos permite retornar estructuras, y mucho menos una lista de estas. Por ello tenemos la función getNumProposals() que nos devolverá el número de propuestas existentes en la Blockchain y getProposal(uint proposalInt) para obtener estas una a una.

En la función vote(uint proposalInt, uint voteValue) comprobaremos en las primeras líneas que ningún usuario vote una propuesta repetidas veces y que el voto es correcto.

Como podéis comprobar, Solidity es un lenguaje singular, con sintaxis muy parecida a TypeScript, pero que según lo que queramos hacer puede no resultar tan natural como este. Debemos recordar que es un lenguaje moderno, sin demasiado tiempo de historia.

Si queréis tener un poco más de soltura con Solidity os recomiendo que echéis un vistazo a su documentación oficial. Está cargada de ejemplos e incluso está traducida al español: https://solidity-es.readthedocs.io/es/latest/.

Testeando el contrato inteligente /test/voting.js

Antes de consumir los datos y operaciones de nuestro contrato inteligente desde el frontend, podemos testear de un modo muy cómodo con Truffle. Que nos permite hacerlo con Solidity o con Javascript. Yo he elegido escribir los tests con Javascript porque me resulta más cómodo. Truffle hace un wrapper sobre el framework javascript de desarrollo de test Mocha.

Una vez los tenemos escritos, podemos ejecutarlos fácilmente con el siguiente comando:

> truffle test

Consumiendo el contrato inteligente desde el cliente javascript /src/js/app.js

Desde este archivo interactuamos tanto con el contrato inteligente, consultando y añadiendo datos, como con el HTML, modificando la información de los nodos con jQuery.

Las primeras funciones son necesarias para la instanciación de web3 y del contrato inteligente desarrollado “Voting”.

El resto de funciones son para obtención y añadido de datos en el sistema. Si echamos un vistazo a getProposals(), podemos ver cómo para obtener los datos de todas las propuestas primero usamos la llamada getNumProposal() para conocer el número de propuestas almacenadas, y una vez conocido este número podemos iterar para obtenerlas una a una. Luego, con jQuery rellenamos los campos de HTML.

La función handleEvent() la usaremos para actualizar los datos mostrados en pantalla una vez que la blockchain crea los nuevos bloques.

Continuación del trabajo

Además del despliegue en local usando Ganache como hemos visto, es posible que nos interese compartir nuestra DApp con el resto de usuarios para que nos ayuden a testearla o incluso la usen. Para ello la Blockchain de Ethereum dispone de testnet y mainnet respectivamente.

Yo he usado la testnet Ropstem y la plataforma Heroku para el despliegue de nuestra DApp. Para ello he habilitado otro repositorio de GitHub:

Trabajo para el futuro

Aquí termina el tutorial, pero, si a raíz de este alguien tiene ganas de seguir desarrollando le propongo algunas funcionalidades que podría incluir:

  • Propuestas con fecha/hora de inicio y fin. Así, solo aparecerán en pantalla aquellas propuestas que estén dentro del rango de tiempo acordado.
  • Anonimato total para los usuarios.

¡Contáctame por github si tenéis dudas o ganas de que trabajemos juntos!