Blockchain: Desarrollar aplicaciones descentralizadas en Ethereum

Ahora que ya sabes qué es Blockchain, hoy vamos a ver una de sus implementaciones y cómo se desarrolla sobre la misma. En el artículo anterior hablamos fundamentalmente de dos implementaciones: Bitcoin y Ethereum, ya que son las más populares a día de hoy. Hoy vamos a centrarnos en la segunda, la cual fue lanzada en el año 2015 y es open source. En Ethereum es posible programar un tipo de aplicaciones llamadas DAPPs, de Distributed Applications, lo cual va más allá de mandar divisas de una cuenta a otra. Además, el tiempo de minado de un bloque es bajo (segundos), respecto a Bitcoin, donde es de 10 minutos, por lo que es más conveniente a la hora de desarrollar aplicaciones. Por último, otro de los puntos importantes es que esta implementación ha tenido muy buena adopción en el mundo empresarial, por lo que empresas como Microsoft, Google o Amazon ofrecen servicios que te facilitan su implementación. En este artículo vamos a ver cómo empezar a desarrollar en Ethereum.

Las transacciones en Ethereum

Antes de comenzar a desarrollar, es importante que sepas qué aporta Ethereum como implementación de Blockchain en diferentes puntos, entre ellos las transacciones.

Si recuerdas, las transacciones son el contenido principal de la cadena de bloques. Cuando hablamos de monedas digitales, como Bitcoin, estas tienen básicamente los siguientes valores:

  • From: es la dirección dentro de la red de Blockchain de la cuenta del usuario desde la cual se realiza la transacción. En Blockchain los usuarios tienen un identificador que representa su cuenta desde la cual pueden enviar y recibir dinero digital. Estas cuentas no tienen nada que nos indique quién es ese usuario (no aparecen sus nombres o apellidos, o un id que relacione el usuario con su información fiscal), por lo que solo seremos dueños de una cuenta siempre y cuando tengamos en nuestro poder la clave privada de la misma. Para verificar que una transacción la ha hecho un usuario, estos firman las transacciones con esta clave privada.
  • To: la dirección de la cuenta del usuario que va a recibir la divisa.
  • Value: la cantidad que se quiere transferir de una cuenta a la otra.

La primera diferencia es que Ethereum tiene como divisa el ether. Además de los valores mencionados, Ethereum se diferencia del resto de implementaciones porque no sólo pueden enviarse a otro usuario, sino que también se pueden enviar a los llamados smart contracts, los cuales son programas desarrollados por nosotros. En este caso, a parte de los campos mencionados anteriormente, Ethereum aporta unos cuantos más, entre ellos estos:

  • Timestamp: indica el momento en el que ha ocurrido la transacción.
  • Block: el bloque donde se ha incluido la transacción.
  • Txhash: es el identificador de la transacción dentro de la red.
  • Gas limit: indica la cantidad que el usuario está dispuesto a pagar por ejecutar su transacción. Si el precio que ponemos de limite de gas es inferior a lo que cuesta ese tipo de transacción se hará un rollback de la misma y no se ejecutará.
  • Gas used: es el gas final que se cobró al llevar a cabo la transacción.
  • Gas price: el precio por unidad de gas que se encontraba vigente en ese bloque, en el momento de la transacción.
  • Nonce: el valor arbitrario por el que compiten los mineros, explicado en el artículo anterior.
  • Input data: si enviamos dinero a otro usuario quedará vacío, pero si estamos interactuando con un smart contract aquí vendrá el código del smart contract en sí o los datos que necesitamos para interactuar con él.

Si quieres ver una transacción real, existen páginas como etherscan.io, donde puedes ver la red pública de Ethereum.

Es súper chulo, ya que puedes ver en tiempo real los últimos bloques generados, las últimas transacciones que han ocurrido, el precio del ether en dólares, etcétera. Si haces clic en cualquiera de las transacciones verás los campos mencionados anteriormente.

Detalles de una transacción en Etherscan

Lo que más me costó comprender en un principio fue la parte del gas pero, no te preocupes, enseguida entenderás todo 🙂

Las redes Blockchain y el pago a los mineros

Recuerdo hace tiempo cuando todo el mundo quería ser minero de Bitcoin y ganarse un dinero extra. Si recuerdas el artículo anterior, cada vez que toca generar un nuevo bloque, porque ya no caben más transacciones, se deben calcular al menos un par de valores: el hash, que dijimos que era la huella digital que representa los datos del bloque, y el nonce. Obtener el hash de un bloque es muy rápido. Sin embargo, obtener el nonce supone un esfuerzo computacional, lo cual se traduce en un gasto energético por parte de los nodos que forman la red. Para que el hash sea válido, por cada bloque se establece un valor llamado dificultad objetivo para ese bloque. Esto significa que los mineros deben ir modificando el valor del nonce, de manera arbitraria, hasta que el hash resultante quede por debajo de la dificultad establecida. Esto solo puede hacerse a través de fuerza bruta, y es lo que hace que este proceso sea muy costoso. Cuanto más pequeño sea el valor de la dificultad más difícil será calcular el hash.

Para premiar a los mineros, cada vez que son capaces de obtener este nonce, son recompensados con la divisa de la plataforma. En el caso de Bitcoin con bitcoins y en el caso de Ethereum con ethers. Esta recompensa puede ir cambiando con el tiempo, pero en el momento de escribir este artículo la recompensa en Bitcoin son 12,5 bitcoins (hace años era de 50 bitcoins) y en Ethereum es de 3 ethers.

No todos los mineros se llevan la recompensa, sino que lleva a cabo una competición llamada Prueba de trabajo (Proof of Work) y gana el que obtenga el nonce antes. Cuanto mejores sean las capacidades de tu ordenador, más posibilidades tendrás de ganar la competición y ser recompensado. El minero que encuentre el nonce válido, que haga que el hash quede por debajo de la dificultad, lo anunciará al resto de los mineros y estos verificarán que el hash resultante es correcto y que por lo tanto ese minero ha hecho la prueba de trabajo.

Además de la recompensa que un minero recibe por minar un bloque, este también recibirá ethers por las transacciones que lleven a cabo los usuarios. A estos se les cobra una comisión llamada gas. Se creó esta unidad porque el ether fluctúa demasiado, debido a que se negocia públicamente en las bolsas, por lo que era necesaria otra forma de medir más constante. Con esta unidad lo que se valora es el coste computacional de las diferentes acciones en Ethereum. Siempre se compara con los kilovatios de la red eléctrica de casa, o también con la gasolina de un coche. La explicación más sencilla es: alguien está invirtiendo su tiempo, la electricidad de su casa y su ordenador para ejecutar tus transacciones/contratos inteligentes y de alguna forma hay que pagar ese gasto que le estamos generando.

Existen unos valores establecidos de gas para diferentes acciones: Por ejemplo, una transacción de ether de una cuenta a otra tiene un coste de 21.000 de gas. Cuanto más complejos sean los comandos que hay que ejecutar, más gas hay que pagar. Existe una página llamada ETH Gas Station donde puedes incluso estimar estos gastos.

ETH Gas Station

Por ahora con que retengas la idea de que las acciones que se realizan en Blockchain hay que pagarlas es más que suficiente 🙂

Ahora sí: Las aplicaciones distribuídas o DAPPs

Ya he mencionado en varias ocasiones la palabra smart contract, pero no he explicado para qué sirven. En esta sección veremos un ejemplo de su uso.

Los contratos inteligentes son programas desplegados en la red de Ethereum, donde todos los nodos tienen una copia del mismo. Una vez desplegados no pueden ser modificados, debido a la inmutabilidad de la cadena de bloques, por lo que es importante que se prueben muy muy bien.

El lenguaje utilizado para desarrollar estos contratos se llama Solidity, el cual se parece mucho a JavaScript, por lo que la curva de aprendizaje es mínima. Estos contratos, una vez desarrollados en este lenguaje necesitan ser compilados, dando como resultado el bytecode. Este último se enviará a la cadena de bloques en forma de transacción, creando una instancia del contrato en la red, pudiendo ser así utilizado por los usuarios de la misma. Todos los nodos tienen instalados una máquina virtual de Ethereum llamada Ethereum Virtual Machine (EVM), la cual es capaz de ejecutar el código Bytecode de los smart contracts.

Una aplicación distribuida en Ethereum está formada por tres partes:

  • Los datos distribuidos que forman la cadena de bloques.
  • La lógica de los smart contracts.
  • Una aplicación cliente que se conecta con nuestra red y llama a nuestros smart contracts.

Para ver todo esto con un ejemplo vamos a crear un contrato que nos permita registrar los fichajes de nuestros empleados. Esta es una información que no debería de cambiar con el tiempo, por lo que es un escenario claro para la cadena de bloques.

Desarrollando Smart Contracts en Remix

Para poder desarrollar un contrato, necesitas tres cosas:

  1. La definición del mismo en el lenguaje Solidity.
  2. Un compilador que pase dicho código a Bytecode.
  3. Una red de Ethereum de pruebas donde desplegarlo y probarlo.

Existen diferentes opciones, más y menos complicadas de provisionar, pero creo que la más cómoda para empezar es Remix. Se trata de un IDE online que nos permite desarrollar y ejecutar de forma rápida smart contracts. Este se encuentra en http://remix.ethereum.org.

Remix

Como ves, se trata de un editor online donde aparece un código de ejemplo en Solidity y, al lado derecho, un conjunto de pestañas donde puedes compilar el código, ejecutarlo, depurarlo, etcétera.

Desarrollar el contrato en Solidity

Para este artículo, vamos a borrar los dos archivos que aparecen en la carpeta browser y vamos a crear uno nuevo llamado TimeControl.sol. Como te decía, vamos a trabajar para la nueva ley que ha surgido en España, donde los trabajadores deben fichar la hora a la que entran y salen del puesto de trabajo. El cliente final será una aplicación web pero, pensando en el mundo IoT, esto podría ser a través de una tarjeta, de la huella digital, reconocimiento facial, etcétera. Copia el siguiente código en el nuevo archivo:

pragma solidity ^0.5.8;
contract TimeControl{    
    
    address private owner;
    mapping (address => uint[]) private employeeRecords;
    
    constructor() public{        
        owner = msg.sender;
    }
    
   function Register() public{
       employeeRecords[msg.sender].push(now);
   }   
  
   function GetMyRegistries() public view returns (uint[] memory){
       
       uint[] memory result = new uint[] (employeeRecords[msg.sender].length);
       for (uint i = 0;i < employeeRecords[msg.sender].length; i++) {
           result[i] = employeeRecords[msg.sender][i];    
       }
        
        return result;
    }    
}

La primera línea que vemos en nuestro código indica la versión que queremos utilizar de Solidity, en este caso la 0.5.8. Después, como si de una clase se tratara, creamos un contrato utilizando la palabra clave contract y el nombre del mismo. El contenido son variables y funciones, algo a lo que estamos más que acostumbrados.
Lo primero que nos encontramos son un par de variables: la primera de ellas, del tipo address, es para almacenar el propietario del contrato, que es el que mandará desplegarlo en la red de Ethereum. Mapping es como si fuera un diccionario, clave/valor, donde en este caso he asociado un tipo address, que será la dirección de la cuenta de un usuario, que en este caso representará a un empleado, con un array de valores del tipo uint (enteros sin signo) donde almacenaré la fecha y hora de los fichajes que el usuario vaya haciendo en el sistema.
En el constructor asignamos el valor de msg.sender a nuestra variable owner. La variable msg se trata de una de las variables globales que tenemos disponibles.
Después, tenemos una función llamada Register donde lo único que hacemos es añadir a nuestro employeesRecord un fichaje al array del empleado que ejecutó la función.
GetMyRegistries simplemente devuelve los fichajes de un empleado. Al ser una función de lectura, la cual no modifica la cadena de bloques, es gratuita. Este tipo de funciones se marcan con la palabra view.

Como ves, el código es bastante sencillo. Es verdad que hay novedades respecto a otros lenguajes a los que estamos acostumbrados, todas ellas relacionadas con Blockchain (el tipo address, funciones gratuitas marcadas como views, etcétera). Si quieres aprender más sobre el desarrollo de estos contratos te recomiendo el curso de Carlos Landeras en Udemy: Conviértete en desarrollador Blockchain con Ethereum.

Compilar el contrato

Compilar el contrato en Remix es super sencillo: solo debes hacer clic en el botón Start to compile o utilizar la combinación Control + S, en la pestaña Compile.

Compilar un Smart Contract en Remix

Si todo ha salido bien, aparecerá el nombre de tu contrato en un cuadro verde. Es importante que en el combo Select new compiler version esté seleccionada la versión con la que estás trabajando, que fue la que indicaste en la primera linea de tu contrato.

Despliegue del contrato en una red Ethereum

Lo último que nos queda es probar el contrato que acabamos de desarrollar. Para ello, haz clic en la pestaña Run y modifica el valor del combo Environment a JavaScript VM.

En la pestaña Run y modifica el valor del combo Environment a JavaScript VM

Lo que significa es que vamos a utilizar una red de Ethereum ficticia en nuestro navegador. Verás que justo debajo tienes otro combo llamado Account con cuentas de usuarios, también ficticias, las cuales tienen asociado ether (ficticio también) para poder costear las transacciones que se realicen. Esto está muy bien durante el desarrollo, ya que no necesitas instalar ni configurar nada. El último paso para desplegar el contrato es hacer clic en el botón Deploy y, si todo ha salido correctamente, verás en la consola de salida que una transacción ha sido ejecutada correctamente, la cual se corresponde con el despliegue de tu contrato.

Al desplegar un contrato se ejecuta una transacción con el mismo.

Amdeás, comprobarás que en el lado derecho de la pantalla te aparecerá una instancia de tu contrato en el apartado Deployed Contracts. Si expandes el que acabas de crear, verás que aparece todo aquello que tengas como público en tu contrato, en este caso las funciones Register y GetMyRegistries. Puedes invocar ambas utilizando las diferentes cuentas del combo Accounts, simulando que estás llamando al Smart Contract con diferentes usuarios. Después de llamar varias veces a la función Register, GetMyRegistries devolverá los fichajes de la cuenta que tienes seleccionada en el combo. Según vayas ejecutando la función Register con las diferentes cuentas, verás que la cantidad de ether asociada a cada una irá bajando, debido a la comisión de gas que tiene dicha operación.

Remix – El ether de las cuentas va bajando al llamar a la función Register

Por otro lado, cuando llamas a la función GetMyRegistries verás que se te devuelve un array con un conjunto de números, uno por cada vez que has llamado con ese usuario a la función Register.

Remix – Llamada a GetMyRegistries

Estos números son los fichajes del empleado en formato timestamp. Puedes hacer la conversión de cualquiera de los valores del array en esta página. Como ves, se trata de un ejemplo sencillo para arrancar en el mundo de los contratos inteligentes.

Existe otro IDE online, que también me gusta mucho, y es EthFiddle, ya que también te permite compilar y probar tus smart contracts desde el navegador.

EthFiddle

Además, tiene un apartado llamado recent fiddles donde puedes ver los smart contracts de otras personas que han estado haciendo pruebas con el IDE.

¡Saludos!