Blockchain

Blockchain


Blockchain » Capítulo 3. Contratos inteligentes y Ethereum » Más allá de contratos inteligentes

Página 8 de 13

Capítulo 3

Contratos inteligentes y Ethereum

En este capítulo vamos a presentar los denominados contratos inteligentes, sus principales características y su relación con la tecnología blockchain. De forma más pormenorizada introduciremos el sistema Ethereum, su criptomoneda asociada, ether, y cómo realizar contratos inteligentes con esta tecnología. Se comentarán otros aspectos como el ciclo de vida de un contrato inteligente y la visión de futuro de Ethereum.

Los contratos inteligentes (smart contracts), aunque de moda en los últimos años, son en realidad un concepto ideado hace más de dos décadas por Nick Szabo. En un ensayo, en 1994, Szabo previó la confluencia de la informática, la criptografía, las leyes y la economía, para dar lugar a “entes autónomos” que codificarían comportamientos complejos con el fin de resolver, de forma eficiente y segura, diferentes situaciones cotidianas y de negocios. Por ejemplo, pagos automatizados y “propiedad inteligente” capaz de gestionarse a sí misma sin ayuda humana.

Mucho de lo que se ha propuesto en los últimos años bajo el paraguas de las cadenas de bloques tiene su fundamento de negocio en las visionarias palabras de Szabo. Entre otros, su ejemplo de un coche financiado por un banco, que evita ser utilizado en el caso de que su propietario no realice un pago (siempre y cuando el coche no esté en marcha).

Szabo señala que, por un lado, las tecnologías subyacentes y su difusión estaban aún muy inmaduras y, por otro, los casos de uso eran poco conocidos por los tecnólogos. No obstante, con la llegada de la criptomoneda bitcoin en 2008 (Nakamoto, 2008) y la tecnología blockchain que la sustenta, se empezó a vislumbrar la aplicación práctica de estos conceptos. Como veremos a continuación, no es casualidad: los sistemas blockchain combinan las tecnologías que Szabo menciona como potenciales pilares de sus contratos inteligentes.

Contratos inteligentes y funcionamiento en sistemas blockchain

Un “contrato inteligente”, en su representación fundamental, no es más que un programa informático que codifica las operaciones que deben llevarse a cabo dependiendo de sucesos externos al programa. El término “contrato” es debido a que dichas operaciones suelen enmarcarse dentro de un acuerdo entre partes, como el acuerdo de pagar la cuota del coche en el ejemplo anterior. Otro ejemplo frecuente es el de una cerradura de una habitación de hotel que solo se abre para el usuario que ha pagado dicha habitación cuando este lo requiere.

Esta simplificación de los contratos inteligentes ha llevado a muchos a afirmar que estos no son inteligentes, sino que simplemente siguen una serie de instrucciones predefinidas; también se dice que no son contratos, ya que no suelen llevar respaldo legal. Es cierto que en el ensayo de Szabo no se formalizan sus propiedades, más allá de enmarcarlos dentro de un mundo ciberfísico donde lo digital o virtual interactúa con lo físico. No obstante, a continuación se describen de soslayo las tecnologías que los harán posibles y que dotan a los contratos inteligentes de propiedades fundamentales no presentes en un programa informático tradicional. Estas propiedades son:

El resultado producido por un contrato inteligente no es simplemente el obtenido por un ordenador tras ejecutar un código determinado; es, además, el resultado que ha sido consensuado por un conjunto de ordenadores comunicados entre sí.

Dicho resultado se escribe en un registro público de tal manera que es posible detectar posteriores alteraciones del mismo.

El registro público es mantenido para siempre por todos los ordenadores del sistema, o por una parte importante de ellos.

Estas propiedades se heredan, como hemos dicho, de las tecnologías que finalmente se han utilizado para implementar la visión de los contratos inteligentes de Szabo. La primera propiedad anterior se resume en que el resultado de un contrato inteligente es “consensuado” por la red de ordenadores que componen el sistema. Es decir, existe un “protocolo de consenso” que gobierna esta red mediante el cual los ordenadores que la forman deciden cuándo un resultado es válido y cuándo no. La segunda propiedad se refiere a que se preserva la integridad de los resultados que produce un contrato inteligente mediante mecanismos criptográficos. Por último, la tercera propiedad indica que los datos estarán disponibles siempre y cuando sigan quedando ordenadores en la red (y se cumpla el requisito de que al menos la mitad de los ordenadores que componen el sistema son honestos).

Combinando las tres propiedades ya citadas, se consigue una propiedad adicional y esencial, conocida como “inmutabilidad”. Es decir, dado que el resultado de un smart contract es consensuado por toda la red, se escribe de forma que se garantiza su integridad y el registro en el que se escribe se mantiene siempre. Así, en cualquier momento futuro se podrá consultar cuál fue el resultado, con la certeza de que lo que esté escrito en el registro es el resultado que efectivamente produjo el contrato inteligente.

De esta manera, llegamos al punto común entre los contratos inteligentes y los sistemas blockchain: un sistema blockchain está, grosso modo, compuesto por los elementos anteriores (protocolo de consenso, criptografía y registro público), con el fin de proporcionar inmutabilidad sin necesidad de autoridades centrales, de tal manera que es posible ejecutar contratos inteligentes “a la Szabo” usando un sistema blockchain como base tecnológica.

Para concretar lo expuesto, vamos a resumir el comportamiento de un contrato inteligente en el contexto de un sistema blockchain. Omitiendo detalles técnicos, como interfaces y aspectos relacionados con la programación, y simplificando, supongamos que el sistema blockchain del ejemplo contiene un contrato inteligente para bloquear un coche en el caso de que su propietario no satisfaga una mensualidad del préstamo concedido por un banco. Si fuera así, entonces:

El propietario ejecuta la operación de apertura del coche. Esta operación llega a todos los ordenadores de la red (a través del coche, que es uno de estos ordenadores).

Cada ordenador comprueba en el registro inmutable que el propietario no ha satisfecho el último pago. El resultado de la operación de apertura es denegado.

Dicha denegación se escribe en el registro por parte de alguno de los ordenadores que componen la red.

Al detectar la escritura en el registro, el coche tiene la certeza de que el resultado es válido. Rechaza abrirse, informando al propietario del motivo.

Por último, para afianzar el papel de las tecnologías subyacentes, destacamos que la primera operación incluye típicamente una firma digital, de tal manera que se puede verificar quién la origina. La segunda operación implica una iteración del protocolo de consenso de la red, de tal manera que la mayoría de los ordenadores de la red llegan a la misma conclusión. La tercera operación incluye mecanismos de control de integridad, como resúmenes criptográficos, que garantizan que se detectará cualquier cambio no deseado. Todas estas propiedades garantizan la correcta ejecución de las condiciones del contrato inteligente, dotándolo, por lo tanto, de cierta similitud con un contrato tradicional, ya que se cumplen sus condiciones. A la vez dotan al contrato de cierta “inteligencia”, ya que este cumplimiento se hace de forma (prácticamente) automática.

En las siguientes secciones, presentaremos ejemplos concretos de contratos inteligentes, usando como base el sistema blockchain Ethereum.

Fundamentos y diseño de Ethereum

Como hemos visto en el capítulo 2, Bitcoin fue el primer sistema en utilizar una cadena de bloques para representar la información y su evolución. Aunque se suele decir que Bitcoin no soporta contratos inteligentes, esto no es del todo cierto: toda transacción de Bitcoin es en sí misma un contrato inteligente muy sencillo que, de hecho, está compuesto por instrucciones en un lenguaje de programación propio de Bitcoin. Dado que este lenguaje es bastante limitado, las capacidades de un contrato inteligente en Bitcoin son restringidas, aunque los contratos inteligentes que pueden definirse con este lenguaje permiten llevar a cabo todas las tareas para las que fue creado.

Estas limitaciones de Bitcoin dieron lugar al nacimiento de Ethereum, un sistema blockchain diseñado para sustentar contratos inteligentes capaces de ejecutar prácticamente cualquier cómputo.

De forma más concreta, Ethereum es un sistema descentralizado en el que los nodos que lo componen (computadores ejecutando el software específico de Ethereum) se comunican de igual a igual, es decir, forman una red entre pares (P2P). Estos nodos mantienen una copia de la cadena de bloques de Ethereum, que incluye toda la información del estado del sistema. Para entender este estado, es necesario conocer varios conceptos fundamentales, que veremos a continuación.

Cuentas de usuario. Para poder operar en Ethereum, es necesario que cada usuario se cree una cuenta. Cada cuenta es, en realidad, un par de claves pública-privada de un criptosistema asimétrico basado en curvas elípticas (de hecho, se emplea la curva secp256k1, al igual que en Bitcoin). De este par de claves, la parte pública se utiliza para obtener de forma unívoca lo que se conoce como “dirección de la cuenta”. No existe limitación en el número de cuentas que puede tener cada usuario, basta con que se generen varias parejas de claves pública-privada. Cada vez que un usuario quiera ejecutar una transacción en Ethereum, tendrá que elaborar una firma digital con su clave privada. Como se vio en el capítulo 1, cualquiera podrá verificar dicha firma con la clave pública correspondiente. Un aspecto esencial es que, dada la naturaleza descentralizada de estos sistemas, la gestión de las claves privadas es responsabilidad única del usuario. En concreto, si un usuario pierde la clave privada de una de sus cuentas, efectivamente pierde el acceso a dicha cuenta (y todo lo que tuviera en ella). Del mismo modo, si una tercera persona consiguiera el acceso a dicha clave privada, podría controlar la cuenta como si fuera su propietario legítimo. Por ello, es conveniente tomar todas las medidas necesarias para mantener las claves privadas en secreto y sus correspondientes copias de respaldo.

Ether. Cada cuenta tiene un balance asociado en la criptomoneda interna de Ethereum: el ether. Este ether se puede utilizar de dos maneras: bien en transferencias “tradicionales”, en el sentido de enviar una cantidad determinada desde una dirección A a una dirección B; o bien como pago por la creación o ejecución de un contrato inteligente. El balance de cada cuenta está escrito en la cadena de bloques de Ethereum. De hecho, por defecto todas las cuentas existen; simplemente, la mayoría de ellas tienen un balance 0 y no tienen un “propietario”, es decir, nadie conoce o ha generado el par de claves pública-privada correspondiente. La unidad indivisible del ether (el equivalente a los céntimos en el euro) se conoce como wei. Un ether equivale a 1018 wei. Hay otras denominaciones intermedias como szabo (equivalente a 1012 weis) o finney (correspondiente a 1015 weis). Como curiosidad, todos estos nombres se refieren a personajes importantes en la historia de las criptomonedas.

Gas. En Ethereum, cualquier operación que implique cambios sobre el estado de la red (como las transacciones, que veremos a continuación) se traduce en instrucciones en código máquina de Ethereum. Este código será ejecutado por los nodos de la red, lo cual supone que tales nodos dedicarán recursos a satisfacer las peticiones de otros usuarios. Del mismo modo, cualquier valor que sea necesario almacenar en la cadena de bloques consumirá espacio en los nodos que componen el sistema. Por ello, es necesario incentivar a los nodos a que contribuyan con sus recursos de procesamiento y almacenamiento; por lo que es necesario establecer formas de medir cuántos recursos se utilizan, para recompensar justamente a todos los nodos que contribuyan. Para ello, Ethereum utiliza el concepto de gas. Cada operación básica en el código máquina de Ethereum tiene un coste predefinido en unidades de gas, al igual que cada byte de almacenamiento requerido, al que el emisor debe hacer frente.

Transacciones. Son las operaciones que permiten hacer cambios en la cadena de bloques. Es decir, son operaciones de escritura que tienen como objetivo modificar el estado actual de la cadena, por lo que deben estar sujetas a validación. Podemos distinguir tres tipos principales de transacciones: de transmisión de valor, de creación de un contrato inteligente y de ejecución de un contrato inteligente. Los campos que componen una transacción son los siguientes:

Origen (obligatorio): es la dirección de la cuenta que ejecuta la transacción. En el caso de una cuenta de usuario es la dirección que corresponde a la clave pública; en el caso de un contrato inteligente es la dirección asignada al contrato inteligente en el momento de su creación. Técnicamente, puede haber varios “niveles” de origen. Es decir, un usuario U puede crear una transacción para ejecutar un contrato A. Como resultado, este contrato A puede crear otra transacción invocando a otro contrato B, y así sucesivamente. Para evitar ambigüedades, Ethereum distingue entre el origen de la transacción (txOrigin) y el emisor del mensaje (msgSender). El primero siempre será la cuenta del usuario que inició la cadena de llamadas, ya que en el extremo inicial siempre debe haber una cuenta de usuario. El segundo se refiere al salto inmediatamente anterior, que será un contrato inteligente. En el ejemplo anterior, desde el punto de vista de la transacción de A a B, U es el origen de la transacción y A es el emisor del mensaje.

Destino (obligatorio y condicional): es la dirección de la cuenta destinataria de esta transacción. Puede ser una cuenta de usuario, en el caso de transferencias de criptomoneda, o la dirección de un contrato inteligente, en el caso de querer ejecutar alguna de sus funciones. Si es una transacción de creación de contrato, el campo debe dejarse vacío.

Número de transacción (obligatorio). Cada transacción debe llevar un número entero como identificador que debe ser único dentro de las transacciones enviadas por una misma dirección de origen. En Ethereum, estos números son secuenciales para cada dirección de origen.

Valor (opcional): es la cantidad de ether a transferir del origen al destino. Es un valor opcional dado que no todas las transacciones son para realizar pagos.

Gas máximo (obligatorio). Como no siempre es posible determinar de antemano cuál será el coste de una transacción, lo que se hace es especificar una cantidad máxima de gas por la que se está dispuesto a pagar: el gas máximo. Una vez se llegue al límite establecido, la transacción se cancela aunque no haya llegado a completarse. El nodo que ejecute la transacción y la incluya de forma satisfactoria en un bloque será quien se quede con el importe asociado a las unidades de gas consumidas por la transacción.

Precio (obligatorio). Aunque el gas podría medir cuánto cuesta ejecutar una transacción y el gas máximo cuánto se debe pagar por ella, Ethereum incluye un nivel de abstracción más: el “precio”, esto es, el valor que el emisor de una transacción está dispuesto a pagar por cada unidad de gas. Dado que estos conceptos (gas, ether y precio) pueden llevar a confusión, para fijar ideas, consideremos el siguiente escenario ficticio. Supongamos que una persona tiene un coche con un depósito de capacidad máxima, M, con la peculiaridad de que, cuando va a usar el coche, debe llenar el depósito, no necesariamente al máximo de su capacidad. Además, esta persona conoce una gasolinera a la que puede hacer ofertas: puede decirle al propietario cuánto dinero está dispuesto a pagarle por cada litro de combustible. Por supuesto, el propietario puede negarse a servirle si cree que el precio es muy bajo. Por otro lado, si el dueño del coche ofrece un precio muy alto por cada litro de combustible, estará derrochando dinero. Como es lógico, esta persona se preocupará por hacer un buen análisis en dos aspectos: cuál es el precio óptimo a ofrecer por litro y cuánto debe repostar, para no quedarse tirado a mitad de camino. Volviendo a Ethereum, la transacción sería el equivalente a moverse entre dos puntos en el ejemplo del coche. Las unidades de combustible (en litros) que se repostan antes de cada trayecto, y que permitirán hacer trayectos más o menos largos, son en Ethereum las unidades de gas máximo que se especifican en la transacción, de modo que solo se podrán ejecutar, como máximo, tantas operaciones como permitan las unidades de gas especificadas. El precio en euros de cada litro de combustible que el dueño del coche ofrece al dueño de la gasolinera corresponde con el precio en ether que ofrece el emisor de la transacción al minero que la incluya en un bloque. Por último, Ethereum tiene un parámetro global, que es el límite máximo de gas que se puede usar por transacción y que es común a todos los usuarios. En el ejemplo del coche, este parámetro prefijado sería la capacidad máxima del depósito. La introducción de este parámetro adicional tiene dos ventajas importantes. La primera es que crea una especie de mecanismo de priorización: recordemos que el nodo que consigue ejecutar la transacción e incluir el resultado en un bloque, se queda con el importe asociado a la misma. Este importe total se calcula multiplicando el gas total utilizado por el precio que se le ha dado a cada unidad de gas. Por ello, la recompensa será mayor cuanto más alto sea el importe total, y hay más incentivo por ejecutar primero las transacciones con mayor importe. La segunda ventaja es un mecanismo de protección ante fluctuaciones del precio del ether en monedas fiat (en general, euros o dólares): si el precio del ether sube, se puede bajar el precio del gas para amortiguar el coste final de una transacción; mientras que si el precio del ether baja, se puede subir el precio del gas para que ejecutar la transacción siga siendo atractivo para nodos que luego intercambian el ether por dinero fiat.

Datos (opcional). En el caso de que la transacción represente la intención de desplegar un nuevo contrato inteligente en Ethereum, es necesario especificar el código fuente de dicho contrato para que el resto de nodos puedan comprobar si es un contrato válido. Igualmente, si la transacción pretende ejecutar una función de un contrato inteligente ya existente (más adelante detallaremos con precisión el concepto de función de un contrato), puede ser necesario que dicha función requiera parámetros de entrada. En ambos casos, los datos asociados se incluyen en este parámetro de la transacción.

Por último, conviene enfatizar el “modelo transaccional” adoptado por Ethereum. En el capítulo 2 vimos que Bitcoin sigue el modelo conocido como UTXO. En el caso de Ethereum, se optó por un modelo basado en cuentas, que es al que estamos acostumbrados en nuestro día a día cuando hacemos operaciones bancarias, es decir, cada cuenta tiene directamente un balance en ether, escrito en la cadena de bloques, de modo que cuando una cuenta es el origen de una transacción, su balance se reduce, y aumenta cuando es el destino.

Contratos inteligentes. Como ya hemos mencionado brevemente, un contrato inteligente es un programa creado por algún usuario de Ethereum y desplegado dentro del sistema, de modo que cada contrato tiene asociada una dirección única. Desplegar un contrato no es más que “empaquetar” el código del programa dentro de una transacción de Ethereum, formateada para indicar que se quiere crear un nuevo contrato en el sistema. Los contratos inteligentes de Ethereum están compuestos por:

Variables globales: son similares a los atributos de un objeto en programación orientada a objetos y se pueden utilizar a modo de “memoria persistente” del contrato.

Funciones públicas: son funciones ejecutables desde el exterior, es decir, por parte de usuarios o de otros contratos inteligentes. Por similitud con lenguajes de programación orientada a objetos, es normal referirse a las funciones como métodos.

Funciones internas o restringidas: son funciones ejecutables únicamente por parte de otras funciones del contrato. Análogamente a las funciones públicas y por similitud con lenguajes de programación orientada a objetos, es habitual referirse a ellas como métodos.

Balance propio. Dado que un contrato puede ejecutar transacciones (incluyendo la creación de nuevos contratos y llamadas a otros contratos), también debe ser capaz de realizar pagos. Por ello, los contratos inteligentes en Ethereum tienen un balance asociado.

En cierto modo, un contrato inteligente en Ethereum puede verse como una cuenta o incluso como un usuario del sistema. No obstante, la dirección de un contrato inteligente, al contrario que la dirección de la cuenta de un usuario, no se deriva de la clave pública de un par asimétrico de claves. En su caso, la dirección del contrato se deriva de varios valores públicos obtenidos en el momento de desplegar el contrato. Ya hemos mencionado que un usuario puede generar tantas cuentas como quiera; un contrato, no obstante, no puede generar cuentas (sí otros contratos) ni puede tener varias direcciones. De hecho, la forma de calcular la dirección de los contratos procede de una propiedad inherente de los mismos: no tienen almacenamiento privado. Esto es así porque tanto su código como sus variables son almacenadas “en claro” en la cadena de bloques. Por lo tanto, todos los nodos de la red tienen acceso a su información. De esta manera, si la dirección de un contrato se calculara basándose en una clave pública, todas las transacciones que emitiese ese contrato deberían firmarse con la clave privada correspondiente. Esto hace que las cuentas de usuario se suelan llamar también Externally Owned Account o EOA (algo así como “cuenta de propietario exterior”). Más adelante veremos por qué el resultado de una transacción que se escribe en la cadena de bloques es correcto.

EVM. Un componente fundamental, y una de las principales innovaciones de Ethereum, es lo que se conoce como máquina virtual de Ethereum o EVM (Ethereum Virtual Machine). La EVM define un conjunto de instrucciones fundamentales en un lenguaje de programación, tipo ensamblador, denominado Solidity, al que se compilan los contratos inteligentes de alto nivel. Además, proporciona los mecanismos para ejecutar de forma unívoca estas instrucciones en ensamblador. Esto garantiza que, partiendo del mismo estado inicial (que se obtiene del último bloque de la cadena de bloques de Ethereum), todos los nodos del sistema producirán el mismo resultado. Dicho de otro modo, la EVM se encarga de evitar que el resultado obtenido por los nodos del sistema sea diferente, dado que estos utilizan entornos de procesamiento distintos, aunque todos ellos empleen el mismo estado inicial. Es decir, garantiza el “determinismo” del sistema. Pero además, tiene otro papel fundamental: ya hemos comentado que, en Ethereum, cada operación tiene un coste asociado, donde “operación” en realidad significa instrucción de código máquina (por ejemplo, una instrucción de salto tiene un coste de 1 unidad de gas). Esto permite calcular, en tiempo de ejecución, el coste real, en unidades de gas, que supone ejecutar un método de un contrato. Más aún, gracias al determinismo de la EVM, este coste será igual para todos.

Consenso. El mecanismo de consenso en Ethereum es de tipo PoW, al igual que en Bitcoin. Es decir, hay que dedicar esfuerzo computacional a una tarea predefinida. Recordemos que en el caso de consenso por prueba de trabajo, a los nodos que se dedican a hacer estos cómputos se los conoce como mineros. En el caso de Ethereum, los mineros utilizan un algoritmo llamado Ethash, diseñado para ser más resistente a optimizaciones hardware. Es decir, hace que sea más complicado y costoso crear hardware específico para esa tarea, lo cual ha provocado la creación de granjas de minado que suponen un riesgo de recentralización. Brevemente, Ethash sigue los siguientes pasos:

Crea una semilla aleatoria utilizando la función resumen Keccak-256 (véase capítulo 1) sobre valores derivados de los bloques previos de la cadena.

Crea una memoria de 16 MB utilizando la función resumen Keccak-512 sobre valores derivados de la semilla aleatoria previa.

Crea un conjunto de datos aleatorios de 1 GB utilizando la función resumen Keccak-512 sobre valores derivados de la caché de 16 MB.

Este proceso se repite aproximadamente cada 30.000 bloques. El cálculo de una memoria de 16 MB, además del conjunto de datos final de 1 GB, permite que clientes con software de pocos recursos puedan verificar los nuevos bloques sin necesidad de dedicar 1 GB de almacenamiento. La resistencia a optimizaciones hardware se debe a que el algoritmo es muy intenso en cuanto a operaciones de lectura y escritura en memoria RAM, tarea que es difícil de optimizar en hardware, al contrario que el cálculo de una función resumen, que consume pocos recursos.

No obstante, Ethereum está trabajando para migrar a un consenso del tipo prueba de interés o PoS (Proof of Stake). Este tipo de protocolos de consenso, más recientes que los de prueba de trabajo, se basan en la asunción de que quienes hayan depositado más “interés” en el sistema (típicamente en forma de inversión económica directa o indirecta), probablemente tengan más motivos para querer garantizar su correcto funcionamiento y, por lo tanto, se puede confiar más en sus decisiones. Este “interés” suele traducirse de una forma u otra en la criptomoneda interna del sistema blockchain. El protocolo al que Ethereum migrará se conoce como Casper. Esta migración tendrá lugar en la versión conocida como Serenity, aún sin fecha pública de lanzamiento.

Otras propiedades y conceptos importantes

Ethereum tiene propiedades importantes que, aunque pueden deducirse de las explicaciones anteriores, conviene comentar explícitamente, de forma breve.

Por un lado, público y no permisionado. Todas las transacciones que tienen lugar en Ethereum, al igual que las de Bitcoin, son accesibles públicamente por cualquiera que se instale un nodo, es decir, son cadenas de bloques públicas. De la misma manera, cualquiera puede instalarse un nodo en Ethereum y llevar a cabo cualquier tarea; es decir, es un sistema que no requiere permisos (no permisionado).

En segundo lugar, seudoanonimato. Ethereum proporciona lo que se conoce como seudoanonimato. Cuando un usuario quiere operar en Ethereum, debe crearse un par asimétrico de claves pública-privada. La clave pública, o un valor derivado de la misma, funciona a modo de identificador para realizar operaciones. Por supuesto, se pueden crear tantos pares de claves como se quiera, pero toda operación llevada a cabo por una misma clave será trazable por dicha clave. Esto es lo que hace que sea un sistema seudoanónimo en lugar de anónimo.

En tercer lugar, encontramos el lenguaje de programación de contratos inteligentes. Ya hemos comentado que el lenguaje de programación de Bitcoin, utilizado para definir qué condiciones deben cumplirse para que una transacción sea válida, es de bajo nivel y relativamente limitado. Ethereum ha tenido varios lenguajes de programación de contratos inteligentes (LLL, Serpent y Solidity). El utilizado actualmente, Solidity, es un lenguaje de alto nivel bastante similar a los lenguajes tradicionales de programación orientada a objetos. De hecho, se suele decir que Solidity es un lenguaje Turing completo, lo que quiere decir que puede calcular cualquier función computable. Aunque, siendo estrictos, esto no es completamente cierto, ya que un contrato inteligente en Ethereum, implementado en Solidity, no puede ejecutarse de manera indefinida debido al límite de gas que se define de antemano.

Por último, el almacenamiento. También hemos comentado que los contratos inteligentes pueden tener variables globales, que son persistentes. Es decir, su valor no se restablece tras acabar la ejecución del contrato inteligente. Esto implica que debe escribirse en la cadena de bloques, lo cual significa que la propia cadena puede usarse para almacenar información. No obstante, también hemos comentado que hay que pagar por cada byte utilizado y, precisamente, el almacenamiento es uno de los recursos más caros en Ethereum, así que suele ser conveniente mantenerlo en el mínimo imprescindible.

Ejecución de un contrato inteligente en Ethereum

Conocidos los principales conceptos relacionados con Ethereum, presentaremos el ciclo de vida de un contrato inteligente desde su creación hasta su (posible) destrucción, pasando por las ejecuciones de sus funciones.

Supongamos que ya existen n cuentas de usuario, cada una con su par de claves asimétricas, y que todos los usuarios conocen las direcciones de los demás. Sin entrar en detalles de código fuente para facilitar la comprensión, trataremos simplemente con un contrato inteligente que, al crearse en la red, permite inicializar una variable interna con un valor entero arbitrario. Al inicializarse, además, el contrato memoriza la dirección de su creador, a quien nos referiremos como usuario U. Posteriormente, solo este creador podrá cambiar el valor de la variable interna, aunque cualquiera podrá consultar cuál es el último valor almacenado. En general, el proceso de creación de un contrato es como sigue:

El usuario U crea una transacción especificando los valores siguientes: origen, datos, gas máximo, precio (en ether) y número de transacciones del emisor.

El usuario U firma la transacción utilizando su clave privada. El resultado de esta firma se incluye como parte de la transacción que se envía a la red.

El protocolo de comunicaciones P2P subyacente hace que la transacción se difunda a (gran parte de) los nodos de la red. Entre estos nodos, habrá mineros buscando crear nuevos bloques.

Los mineros compiten por crear un nuevo bloque, en el que incluyen las transacciones que más incentivos les ofrecen (en forma de importes más altos, como ya vimos). Suponiendo un importe razonable, antes o después algún minero incluirá la transacción enviada por U anteriormente. Cada minero comprueba que cada una de las transacciones que quiera incluir en el siguiente bloque es correcta. Cuando algún minero incluya en el bloque que cree la transacción construida en el punto 1 y enviada en el punto 2, será el momento a partir del cual la transacción existirá en la cadena de bloques y será cuando el código se convierta en un contrato inteligente. Se le asignará una dirección única que depende de la dirección del usuario que lo envía y del número de transacciones que este haya enviado hasta el momento. Nótese que cualquier nodo del sistema puede comprobar que la dirección asignada es correcta. Por otra parte, aunque la transacción ya exista en la cadena de bloques, no significa que sea irreversible. De hecho, al igual que en Bitcoin —y que en cualquier sistema blockchain basado en prueba de trabajo— es necesario que se añadan nuevos bloques después del recién creado para ir aumentando la certeza de que no se revertirá la transacción.

Cada nodo del sistema que reciba el nuevo bloque verificará que los cálculos que hizo el minero que ha propuesto el bloque son válidos. En caso de que lo sean, aceptará el nuevo bloque.

Llegados a este punto, y suponiendo que se ha producido un número razonable de confirmaciones después del bloque que contiene el contrato inteligente recién creado, cualquier nodo de la red tendrá acceso al mismo. La creación de la transacción, firma digital, bloque y los intercambios de mensajes asociados se indican esquemáticamente en la figura 9.

Figura 9

Esquema de la creación de una transacción, firma digital, bloque y los intercambios de mensajes.

Supongamos ahora que el mismo usuario U quiere establecer el valor de la variable interna a un valor concreto. El proceso que seguiría sería el siguiente:

U crea una transacción con la dirección del contrato como dirección de destino y en la que, en el campo data, especifica qué método quiere ejecutar dentro del contrato, además del valor al que quiere establecer la variable interna. Por supuesto, también especifica el resto de los valores obligatorios: dirección origen, gas y precio.

U firma la transacción con su clave privada, envía esta transacción al resto de nodos de la red, incluyendo el resultado de la firma dentro de la propia transacción.

El protocolo de comunicaciones P2P hace que la transacción se difunda a los nodos de la red, entre los que habrá mineros deseando crear nuevos bloques.

Los mineros compiten por crear un nuevo bloque. Cada minero comprueba que cada una de las transacciones que quiera incluir en el siguiente bloque esté bien formada; en este caso, al tratarse de la ejecución de un método de un contrato inteligente, simula esta ejecución dentro de su EVM. Si, como resultado de esta ejecución no se produce un error o una excepción, el minero actualiza la memoria persistente del contrato para reflejar la ejecución de la transacción. En este ejemplo, una posible excepción sería que quien invoca el método del contrato para establecer el valor de la variable interna no es el usuario U. Otra excepción, más genérica, podría ser que el gas máximo especificado no sea suficiente para ejecutar el contrato inteligente. Suponiendo que todo es correcto, en este caso, la ejecución de la transacción implica que la variable interna del contrato creado anteriormente se establece al valor indicado en la invocación anterior. El nuevo bloque calculado por el minero incluye esta transacción (entre otras, potencialmente) y los cambios en el estado de la cadena de bloques.

Cada nodo del sistema que reciba el nuevo bloque verificará que los cálculos que hizo el minero que ha propuesto el bloque son válidos. En caso de que lo sean, aceptará el bloque. Por cada nuevo bloque que extienda la cadena, más difícil será revertir la transacción.

Por último, supongamos que un usuario distinto de U, por ejemplo V, intenta modificar el valor de la variable interna. V seguirá un proceso similar al que se ha explicado para U, con la diferencia de que firmará la transacción con una clave privada distinta de la de U. Los mineros que reciban dicha transacción, al ejecutar la lógica del contrato inteligente existente en la red, se darán cuenta de que la dirección de V no coincide con la de U, que había sido apuntado como el propietario del contrato. Habiéndose especificado como parte del código del contrato que solo su propietario puede modificar la variable interna, esto provocará una excepción, y la ejecución del código se detendrá, rechazando la transacción.

Componentes de Ethereum

A grandes rasgos, los apartados anteriores nos permiten hacernos una idea de las propiedades que garantiza Ethereum y de su modo de funcionamiento. Para un mayor detalle, lo más recomendable es consultar el conocido como yellow paper (Wood, 2015), en el que se expone el modelo formal de Ethereum.

En lo que sigue, presentaremos cómo se puede interactuar con Ethereum y cuáles son las mejores aplicaciones y herramientas para ello.

Si lo que queremos es crear una cuenta para Ethereum y gestionar ether, probablemente la mejor opción sea lo que se conoce como wallet o billetera. Un wallet no es más que una herramienta que permite gestionar las claves criptográficas asociadas unívocamente a cada cuenta (dirección) que se crea. Ya hemos visto que en Ethereum, para demostrar ser el propietario de una cuenta concreta (cuya dirección es una codificación de una clave pública), hay que emitir una firma digital con la clave privada asociada. Por lo tanto, es necesario guardar de forma segura dicha clave privada, para lo que se hace uso de la herramienta wallet. El nombre viene de que, en última instancia, un wallet permite gestionar dinero en forma de ether y, si se pierde dicho wallet, se pierde el dinero asociado; si lo roban, el ladrón puede hacer uso del dinero. En concreto, un wallet en Ethereum (y en cualquier criptomoneda) no almacena el ether en sí mismo, sino que almacena las claves privadas que permiten hacer uso de dicho dinero. Que haya criptomonedas asociadas a una dirección concreta viene definido por los “apuntes contables” escritos en la cadena de bloques y que están asociados a dicha dirección.

Hay diferentes wallets; entre los más populares están Ethereum-Wallet, de la fundación Ethereum; MetaMask, disponible como plugin para los navegadores principales; y MyEtherWallet, disponible como aplicación web y como aplicación de escritorio.

No obstante, han surgido herramientas más avanzadas que un wallet. Sin ir más lejos, el tipo de aplicaciones que se construyen basados en contratos inteligentes en un sistema blockchain se conoce como “aplicaciones descentralizadas” (dapps). Son descentralizadas porque no hay un único servidor que decida si se acepta o no una ejecución, sino que todos los nodos de la red deben ponerse de acuerdo.

Las dapps utilizan información de la cadena de bloques y procedimientos de los contratos inteligentes asociados. Por lo tanto, saber leer esa información y operar según la misma es algo que queda fuera del alcance de un wallet, que solo permite emitir firmas digitales. Para ello, Ethereum proporciona navegadores de dapps, que son herramientas que permiten buscar e interactuar con aplicaciones descentralizadas, ejecutando los métodos que definen.

Este ecosistema de dapps se conoce en Ethereum como la web 3.0. Para entender el concepto más fácilmente, un navegador de dapps se puede considerar como el equivalente a cualquiera de los navegadores web que solemos emplear al acceder a Internet. Si un navegador web permite encontrar e interactuar con el contenido almacenado en Internet, los navegadores de dapps también ofrecen la funcionalidad de wallet. Los principales navegadores de dapps son Mist, de la fundación Ethereum, y Parity, de la compañía homónima cofundada por uno de los cofundadores de Ethereum.

Tanto los wallets como los navegadores de dapps incluyen nodos para conectarse a la red de Ethereum. Pueden ser “nodos completos”, que se descargan una copia completa de la cadena de bloques de Ethereum, o “nodos ligeros”, que solo se descargan un subconjunto de la misma (normalmente, las cabeceras de los bloques y de las transacciones que afectan directamente a las cuentas de usuario que almacenan). No obstante, es posible descargarse directamente un nodo que no incorpore funcionalidad de alto nivel para navegar e interactuar con dapps o sin la interfaz gráfica de un wallet. De hecho, las distintas implementaciones de los nodos de Ethereum permiten hacer prácticamente cualquier operación y, por ello, se puede decir que son la “navaja suiza” del ecosistema. El nodo más extendido, geth, lleva integrado un wallet y permite desplegar e invocar contratos inteligentes en cualquier red de Ethereum, además de explorar la cadena de bloques desde una línea de comandos.

Por último, hay que destacar que, utilizando los nodos de Ethereum que acabamos de comentar, es posible crear redes “privadas” de Ethereum, en el sentido de que pueden hacerse accesibles únicamente a los ordenadores que se configuren para conectarse a ellas (cabe tener en cuenta que “securizar” una red de este estilo puede ser muy complejo). Sin embargo, es importante tener en cuenta que, mientras Ethereum siga teniendo un algoritmo de consenso de tipo PoW, cualquier red privada de Ethereum con pocos nodos puede ser bastante vulnerable a ataques.

Más allá de contratos inteligentes

Para finalizar este capítulo, es importante hacer una breve mención a la visión de futuro de Ethereum. Hasta ahora, hemos hablado principalmente de los principales actores del sistema, de los principales aspectos criptográficos y hemos comentado los principios que están detrás de los contratos inteligentes.

No obstante, la visión de Ethereum va más allá. En realidad, Ethereum se compara con un ordenador global al que todo el mundo tiene acceso. Los contratos inteligentes, ejecutados de forma descentralizada a través de la mencionada EVM, representan la capacidad de cómputo de dicho ordenador global. Pero para poder considerarse un ordenador completo, hay otros aspectos que necesitan ser cubiertos.

En concreto, es necesario proveer de un sistema de almacenamiento persistente escalable. Aunque ya hemos visto que los contratos inteligentes pueden almacenar información, esta información se replica en todos los nodos completos de la red, es decir, los que guardan una copia total del sistema. Este aspecto no es escalable dado que no basta con añadir un nuevo nodo para aumentar la capacidad total de almacenamiento. Por ello, cada byte de almacenamiento persistente en la cadena de bloques es muy costoso. La visión de futuro de Ethereum es incorporar un sistema de almacenamiento distribuido, criptográficamente protegido, que haga más eficiente este almacenamiento persistente. El subsistema del ordenador global de Ethereum que intenta resolver este aspecto se conoce como Swarm. Cabe destacar que, aparte de Ethereum, hay sistemas que hacen de la tarea de crear un sistema seguro de almacenamiento distribuido su objetivo principal, como el sistema de ficheros interplanetario o IPFS (InterPlanetary File System).

Por otro lado, también es necesario incorporar sistemas eficientes de comunicaciones de información que no necesariamente deba ser escrita en la cadena de bloques. Por ejemplo, dos dapps, como parte de su funcionamiento normal, podrían necesitar intercambiar información antes de hacer una transacción para saber qué direcciones de usuario utilizar al ejecutar una transacción que vendrá a continuación. Utilizar la cadena de bloques para este intercambio sería contraproducente y, de hecho, como hemos mencionado en el párrafo anterior, bastante caro. Por eso, en Ethereum se está trabajando para incorporar mecanismos que permitan realizar este tipo de comunicaciones. El subsistema que se encargaría de esta funcionalidad se conoce como Whisper.

Ir a la siguiente página

Report Page