El Rey del Ether

Un fallo esencial para comprender por qué hay que andarse con cuidado antes de deployear un smart contract.

Lautaro Barceló
Boske
5 min readMar 16, 2021

--

El caso presentado a continuación nos sirve de advertencia para aquellos que estamos aprendiendo a programar Smart Contracts en Solidity y tenemos prisa por terminar nuestro código. Antes de deployear un contrato es indispensable tener en cuenta todas las recomendaciones de seguridad y hacer los testeos pertinentes. Los Smart Contracts contienen transacciones y las mismas conllevan una mayor responsabilidad debido a sus peligrosas consecuencias muy difíciles de revertir.

King of the Ether fue una especie de juego de apuestas en formato Smart Contract que estuvo operativo en la red Ethereum desde Febrero de 2016. La dinámica del juego era la siguiente:

  • El trono del Rey del Ether puede ser propio pagando un precio
  • Supongamos que el precio actual para reclamar el trono es de 10 ETH.
  • Te gusta cómo suena ser el Rey del Ether, así que enviás 10 ETH al contrato.
  • Esto te convierte en el nuevo e ilustre Rey del Ether. Tu nombre se añadirá al Salón de los Monarcas en el Blockchain.
  • El contrato entonces enviará 10 ETH (descontando una pequeña comisión) al Monarca anterior, como compensación por la usurpación.
  • El precio para reclamar el trono sube un 33%, a 13.3 ETH, siendo el tope de 10.000 ETH.
  • Si un usurpador viene dispuesto a pagar 13.3 ETH, el mismo te desposará y se convertirá en tu reina, recibiendo el rey un pago de 13.3 ETH (menos comisión) como compensación. Una pequeña ganancia para el rey.
  • Sin embargo, una antigua maldición cae sobre el trono: cada Monarca muere una vez que su reinado alcanza los 14 días. Ninguna compensación se le paga si eso sucede y el precio por reclamar el trono vuelve a su precio original de 0.5 ETH.

La primera versión de KotE tenía algunas leves diferencias con la dinámica de juego que acabo de relatar, pero su código más o menos integraba todas estas reglas. Sin embargo, no duró ni dos días hasta que los problemas se volvieron evidentes y las quejas empezaron a llegar en Reddit. El código había sido testeado en las primeras versiones de Remix con un entorno virtual, pero no había sido testeado en la realidad. Esto produjo un desfasaje entre los costos de gas previstos y los costos de gas reales.

Se puede decir que hay dos tipos fundamentales de cuentas vinculados en una transacción: las cuentas externas, usualmente controladas por un humano mediante una wallet con su propia address, y las cuentas de contratos que son intrínsecas al Smart Contract y también tienen una address. Al realizar cualquier operación con un contrato, hay que tener en cuenta el costo del gas. El gas es un pequeño pago que va a manos de los mineros que mantienen la red Ethereum y el almacenamiento en el Blockchain. El gas es pagado por la cuenta externa que realiza la transacción. Cuando se realiza una transacción, el gas que no se usa es devuelto.

El contrato funcionaba bien cuando el aspirante a Rey enviaba su pago a la cuenta del contrato. El problema ocurría cuando el contrato tenía que enviar la compensación al rey usurpado: el mismo incluía un límite para el pago de gas de 2300 gwei. Al no poder realizar la transacción, el contrato se quedaba con todas las transferencias que ingresaban, con nuevos reyes pero sin compensaciones para los que ya no ostentaban la corona. Este problema tuvo que solucionarse manualmente, haciéndose responsables los creadores del contrato y retribuyendo a aquellos que en buena fe habían perdido su esperado retorno de acuerdo a las reglas del juego.

Los desarrolladores de KotE dieron en su página web una explicación profunda y detallada del bug que provocó el mal funcionamiento del juego. Contando su experiencia, buscaron alertar sobre los posibles peligros de un contrato mal diseñado. A bien saber, Solidity avanzó muchísimo como lenguaje desde entonces evitando muchos problemas de seguridad, aunque sigue siendo un lenguaje en constante desarrollo.

La línea específica de código que provocó el problema fue la siguiente: currentMonarch.etherAddress.send(compensation);

De acuerdo a la documentación de Solidity:

Send es la contrapartida de bajo nivel de transfer. Si la ejecución falla, el contrato actual no se detendrá con una excepción, sino que send devolverá false.

La recomendación que hacen los desarrolladores de KotE es evitar el llamado directo a send a menos que se esté seguro de que la cuenta sea una cuenta externa o un contrato que no necesite más de 2300 gwei, que es la tarifa prefijada de Gas Limit de las funciones send y transfer.

En la documentación de Solidity contamos con un ejemplo de cómo podemos organizar un sencillo código que cumpla la consigna principal del juego de una forma muy sencilla.

Ejemplo de un contrato seguro

Este ejemplo lo podemos ver en el siguiente video que demuestra su funcionamiento.

Para convertirnos en reyes alcanza con ingresar un value superior al que ingresó el rey anterior y llamar la función becomeRichest. Una vez que hemos perdido la corona, con la función withdraw recibiremos nuestro premio.

Como contraejemplo, nos muestra cómo es que llamar a send puede ser sensible a ataques malintencionados.

Ejemplo de un contrato sensible a ataques

De acuerdo a la documentación de Solidity:

Nótese que, en este ejemplo, un atacante puede bloquear el contrato en un estado inútil haciendo que richest sea la dirección de un contrato que tiene una función fallback que falla (ej. usando revert() o simplemente consumiendo más de 2300 de gas). De esa forma, cuando se llama a transfer para enviar fondos al contrato “envenenado”, fallará y también fallará la función becomeRichest, bloqueando el contrario para siempre.

Por el contrario, si usas el patrón “withdrawl” del primer ejemplo, el atacante sólo puede causar que su propio withdrawl falle y no el resto del contrato.

Fuentes

Documentación de Solidity https://docs.soliditylang.org/en/v0.8.2/

King of the Ether https://www.kingoftheether.com/thrones/kingoftheether/index.html

--

--

Lautaro Barceló
Boske

Estudiante de IA y 日本語, desarrollador y productor musical. Llenando la incompletitud esencial.