Implementación de Oráculos en un Smart Contract de Ethereum

Ernesto Garcia N
Blockchain Academy Mexico
7 min readAug 1, 2019
Este tutorial/lectura requiere un nivel previo de entendimiento sobre smart contracts en Ethereum.

Brief

Dentro del ecosistema Blockchain, los Smart Contracts son uno de los principales pilares, y dentro de sus propiedades, existe la particularidad de que, al interactuar con el protocolo de Ethereum, que funciona como una máquina de estados con un comportamiento determinista, tienden a ser autosuficientes por naturaleza.

Es decir, cada actualización de estado se guarda con cada nuevo bloque, lo que hace que la información de la Blockchain sólo pueda entrar a través de un contrato o transacción. Bajo este modelo: no existe forma de escuchar eventos externos sin ser notificado de alguna forma.

Este comportamiento hace que, a pesar de todas las ventajas de utilizar un contrato inteligente para manejar alguna lógica dentro de nuestras aplicaciones, cuando se necesita interactuar con información externa, exista una pieza faltante en el rompecabezas: la conectividad a fuera de blockchain.

Un poco de contexto

Supongamos que has desarrollado una aplicación de pago de servicios, cuyo funcionamiento dependerá enteramente de ,— por ejemplo — , el tipo de cambio, y que, además quieres descentralizar este proceso.

Recordando bien, una de las principales virtudes de la descentralización es la posibilidad de que los datos sean sometidos a auditoría por las partes involucradas, para garantizar la “confianza” de los datos proporcionados.

Ahora bien, “confianza” entre comillas, dado que la confianza es un tema personal, donde los stakeholders deben coincidir. Me explico:

Al crear un contrato inteligente que depende del tipo de cambio, puedes asumir que el precio de 1 Ether permanecerá en 300 USD. No obstante, dada la volatilidad de los mercados, si dejamos ese precio fijo, eventualmente alguien saldrá perdiendo dentro de la ecuación.

Si comunicáramos de alguna forma un smart contract con un API, el resultado de los datos NO ES DETERMINISTA, y puede cambiar con respecto al tiempo.

Tu segunda opción, es que alguien (o algo) proporcione de forma externa ese dato. Sin embargo, esta operación además de requerir un tercero de confianza, puede ser peligrosa, dado que cualquiera que tenga acceso a tus métodos de actualización, puede corromper tu contrato.

¿Qué hacemos entonces? Adivinaste. Necesitamos un oráculo.

¿Qué son los oráculos?

De forma estricta, un oráculo es un servicio que provee información “confiable” a un smart contract a través de transacciones.

¿Porqué transacciones? R: Porque la máquina virtual de Ethereum (EVM) necesita de ether para ejecutarse, y además, limitar su funcionalidad. En este caso, una transacción nos asegura que alguien está pagando por ese poder computacional que ejecuta el cambio de estado.

¿Qué otras formas hay de actualizar el estado? R: El estado del Blockchain se actualiza con transacciones y mensajes. La diferencia entre ellos es que una transacción es generada por una llave privada de una cuenta de propiedad externa, — léase, un usuario — , y los mensajes son generados por una cuenta de contrato.

Normalmente esta información será una serie de eventos volátiles del mundo real, como el clima, el tipo de cambio, las coordenadas de algún activo físico, o incluso la última conexión de un dispositivo (te puedes poner creativo con eso).

Imagen ilustrativa tomada de Toptal

En este caso, utilizaremos Provable (antes Oraclize), que es el proveedor del oráculo que nos entregará datos de un API en cualquier contrato inteligente, solucionando el problema de la conectividad a internet, y más importante, conservando la propiedad de auditabilidad de los procesos de nuestro smart contract.

Implementación

Retomando la idea de implementar una aplicación de pagos que depende del tipo de cambio Ether-USD, necesitamos definir un proveedor “confiable” de datos.

En este caso utilizaremos a Kraken, ya que expone un API gratuita para verificar en tiempo real los precios de varios criptoactivos, y porque tenemos bastante seguridad de que la integridad de los datos se mantendrá, debido a la estabilidad relativa de su servicio.

Kraken markets a 29 de Junio de 2019.

Paso 1 — Plugin de Provable en Remix

Provable nos provee de un plugin para Remix con el cual podemos monitorear el status de una petición a un servicio de datos externo, el que utilizaremos en este ocasión para verificar el funcionamiento de nuestro oráculo.

Para acceder a una versión de remix con el plugin disponible, podemos hacer click aquí.

Sólo hay que asegurarnos de dar click en “OK” cuando tengamos el modal que nos pide añadir el plugin al IDE.

Modal de confirmación para añadir el plugin.

También, hay que tener en cuenta que este plugin funciona solamente con la Javascript VM, así que hay que tener activa esa opción en el environment de Remix.

Environment debe corresponder con la Javascript VM

Podemos comprobar el funcionamiento del plugin en el menú de Remix, hasta el final deberá aparecer la pestaña de Oraclize, y un screen de espera como el siguiente:

Todo correcto :)

Paso 2 — El contrato

El contrato que utilizaremos será pequeño, y simplemente con el objetivo de mostrar cómo realizar una petición al API de Kraken utilizando el servicio de Provable, cuya documentación extensa puedes encontrar aquí.

Dicho contrato puedes encontrarlo aquí completo. No obstante, a continuación explicaré cómo está construido a fondo.

Lo primero que haremos es importar desde Github la versión que utilizaremos de Oraclize (antes Provable). Es importante destacar que Oraclize es un contrato inteligente estándar que se encargará de la parte complicada de la comunicación con el API y de ejecutar las transacciones que actualizarán el estado de la Blockchain.

Dado que la versión de REMIX que adjunté previamente utiliza por defecto el compilador 0.4.24 de solidity, utilizaremos esa versión del API de Oraclize

La versión del compilador de Solidity que utilizaremos en este ejemplo será la 0.4.24. En la segunda línea importamos el API de Oraclize en la misma versión que el compilador, y, posteriormente, heredamos las funcionalidades a través de “is usingOraclize”.

Lo siguiente es crear 2 funciones:

  1. La función __callback(): Es heredada desde el contrato usingOraclize, y será llamada por update() una vez que se confirme el bloque que contiene la transacción que registra los nuevos datos recibidos del API de Kraken.
  2. La función update(): Actualizará los datos haciendo un llamado al API de Kraken para solicitar la información que necesitamos del par ETH/USD.
Captura de nuestras dos funciones que irán dentro del contrato.

Podemos observar que oraclize_query() recibe 2 parámetros:

  1. El Data Source: De acuerdo a la documentación de Provable, tiene que ser uno de los tipos de fuentes de datos permitidos por usingOraclize. En este caso utilizaremos una URL, dado que nos comunicaremos a una API.
  2. Parser Helper junto al endpoint que usaremos: El parser helper convertirá la respuesta del API a nuestro formato de interés. Soporta XML, JSON, HTML y Binario.

Posteriormente analizamos los parámetros y el comportamiento de __callback():

  • myId: Es un id generado por oraclize, y que sirve para hacer búsquedas de operaciones en su query status page. No obstante, para efectos de este tutorial, no lo usaremos .
  • result: Es el resultado de la query que realizamos con update.

function __callback(bytes32 myid, string memory result) public

Ahora analizamos la variable de visibilidad public:

  • La razón por la que esta función __callback() es public, es para que el contrato del oráculo pueda utilizarla. No obstante hay que asegurarnos de que nadie va a actualizar de forma maliciosa nuestros datos usando el callback.

Para ello, Provable nos provee de un método que entrega la dirección del contrato de Oraclize que ejecuta el callback (oraclize_cbAddress), para estar meramente seguros de que la fuente es el oráculo.

require (msg.sender == oraclize_cbAddress())

Finalmente sólo lo guardaremos en nuestra variable de precio inicial.

etherUSD = parseInt(result, 2).

Paso 3— Probando el contrato

Para probarlo, ahora sólo hay que compilarlo y correrlo con la Javascript VM de Remix, y una vez instanciado, consultar la variable etherUSD, para comprobar que se inicializa en 0.

etherUSD regresa 0: uint256:0

Ahora debemos ejecutar la función update para llamar a Kraken, y enseguida, dirigirnos al plugin de Oraclize para verificar el estado de la transacción. Normalmente hay que esperar alrededor de 15 segundos (que aproximadamente es el tiempo de confirmación de cada bloque en Ethereum), y una vez que recibamos el status de actualización correcta, se verá así:

El resultado es: 311.1000 USD por 1 Ether

Finalmente, podemos consultar la variable etherUSD en nuestro contrato, para asegurarnos que tenemos el resultado correcto:

El resultado es de 311.10 (por los decimales).

Y listo, ahora tienes un oráculo funcionando y leyendo correctamente información externa que podrás utilizar para efectuar operaciones no deterministas dentro de un contrato inteligente.

Conclusión

El comportamiento determinista y autosuficiente de la blockchain puede ser un problema para mantener sincronía con datos externos, y que son variables a través del tiempo.

En este pequeño ejemplo, podemos utilizar el resultado de update() cada vez que, -por ejemplo- , queramos ejecutar un pago en ether que tenga una correspondencia directa a USD, en la cuál podremos llamar a update() antes de realizar la transacción correspondiente.

Las posibilidades son bastante amplias, por lo que te recomiendo que revises los Docs de Provable, para verificar las opciones de data sources y parsers que tienes, con los que podrás incrementar las funcionalidades de tu contrato.

Finalmente, me gustaría añadir que Provable no es la única forma de implementar un oráculo. Realmente, Provable es un proveedor, por lo que tú podrías montar tu propio oráculo con cualquier lenguaje de programación que conozcas.

No obstante, este tema será para futuros artículos.

Thanks!

-Ernesto G.

--

--

Ernesto Garcia N
Blockchain Academy Mexico

Ethereum Developer @OpenZeppelin | Intern twice @Google | Blockchain Development Teacher @blockdemy and @platzi