DEV Community

Cibrax
Cibrax

Posted on

Contratos Hibridos, Oraculos y Chainlink

Una de las caracteristicas principales de los Smart Contracts o contratos inteligentes en Blockchain programables como Ethereum es que se ejecutan de manera aislada. Eso signfica que la maquina virtual de Ethereum o EVM ejecuta los contratos en un sandbox en donde solo tienen acceso a los datos locales o datos provistos por otros contratos en la misma red.
La idea de Oraculos aparecen como solucion a esa problematica. Pareciera ser que el termino esta relacionado de alguna manera a la pelicula The Matrix. El oraculo era el personaje que sabia todo sobre la matriz y asesoraba a Neo, el persona principal sobre lo que ocurria en el mundo exterior.
Aplicando el mismo principio, podriamos decir que un oraculo es un smart contrat que sabe como conectarse con aplicaciones o servicios correndo fuera del Blockchain.

En muchos casos, proveen cotizaciones en tiempo real de distintos tokens a los smart contracts que forman parte de los protocolos Defi, y son criticos para el funcionamiento de los mismos.

Un contrato hibrido es un termino que introdujeron los del proyecto Chainlink. Es una combinacion de un contrato que corre en el Blockchain pero tiene acceso a servicios fuera del Blockchain que son provistos por nodos de la red de Chainlink (O mejormente llamados DoNs). En otras palabras, un contrato hibrido seria equivalente a un Oraculo.

Sergey Nazarov, uno de los fundadores de Chainlink hizo incapie en la importancia de los Oraculos para muchos de los protocolos que corren en un Blockchain, y la lanzo esta frase popular, "Un Blockchain sin Oraculos, es como una computadora sin internet".

Los modelos push y pull

Los modelos push y pull hacen referencia al modo en que un Oraculo provee informacion a otros contratos.

En el modelo push, aplicaciones o servicios corriendo fuera del Blockchain estan constantemente actualizando informacion en los contratos que actuan como Oraculos. Otros contratos pueden luego consultar esta informacion a demanda.

Por otro lado, el modelo pull es lo opuesto. Un contrato que necesita acceder a informacion no disponible en el Blockchain llama a un Oraculo a traves de una transaccion. Una aplicacion que esta corriendo por fuera del Blockchain y monitoreando las transacciones hacia ese Oraculo intercepta la transaccion, ejecuta codigo o llama a un servicio externo y devuelve el resultado como otra transaccion al contrato que originalmente llamo al Oraculo.

Chainlink

Chainlink es un proyecto que busca proveer toda la infrastructura que se necesite para poder correr una red de Oraculos que se integran con cualquier Blockchain programable existente (Ethereum y otros).
No es un Blockchain, pero brindan el software para que cualquiera pueda correr un nodo que internamente provee Oraculos que actuan como intemediarios entre Smart Contracts corriendo en un Blockchain y aplicaciones fuera del mismo.

El modelo de negocios de Chainlink es proveer mecanismos para vender datos a las aplicaciones corriendo en el Blockchain. Si un protocolo Defi necesita una cotizacion o algun dato que un servicio externa pueda proveer, los mismos se publican a traves de Oraculos que corren en uno o mas nodos de Chainlink. Esos nodos reciben fracciones del token nativo $Link cada vez que pueden satisfacer alguno de esos pedidos. El token $Link es una implementacion del estandard ERC-677.
La conexion con sistemas externos se realizar a traves un componente llamado "Adapter" o adaptador. Cualquier programador puede crear o implementar un "Adapter"

Cualquiera puede correr un nodo de Link, pero la gracia esta en poder tener acceso a algunos de los adapters que mas se utilizan.
Mucho de ese hosting se lo delegan a socios estrategicos o tambien llamados operadores de nodos. Al fin y al cabo, Chainlink representa en su totalidad al conjunto de todas las redes de nodos que corren su software.

Uno de los aspectos criticos de cualquier procolo de Defi es que no puede confiar en una sola fuente de datos para tomar decisiones. Si esa fuente de datos no esta disponible o brinda informacion erronea, de pronto se vuelve un verdadero problema y puede generar perdidas enormes.
Chainlink ataca ese problema juntando y procesando datos de muchas fuentes y haciendolo disponible a traves de distintos nodos. Si uno de esos nodos deja de responder, los otros lo pueden remplazar. Lo mismo con la calidad de la informacion, si uno de los nodos empieza a brindar datos invalidos, los otros pueden realizar correcciones. Cabe aclarar que esto solo aplica para el price feed de cotizaciones, el cual lo manejan ellos y es uno de los caballos de batalla de este proyecto. Si alguien quiere algo similar, lo tiene que implementar desde cero, y Chainlink no lo provee.

La arquitectura de Chainlink

Image description

Como definicion a alto nivel, una red de Chainlink esta compuesta por nodos. Un nodo es un proceso que esta corriendo todo el tiempo y permite la configuracion de tareas de integracion o que se conectan al Blockchain. Cuando arrancas un nodo, tenes que configurar una clave privada, la cual se usa para firmar cualquier transaccion que el nodo enviee al Blockchain. Si no tenes ningun clave, el nodo automaticamente genera una cuando arranca.
Esa clave tambien tiene que tener fondos en ETH, por que de lo contrario, el nodo no va a poder pagar por el gas para enviar las transacciones. Esa clave privada tambien brinda la contraparte publica o direccion para identificar al nodo.

Las tareas de integracion que corre un nodo con Oraculos en el Blockchain se configuran en algo que se llaman Jobs. Un job esta representado por un documento json que tiene dos partes, una tarea de arranque (initiator) y otras tareas de integracion. La tarea de arranque es la que vigila que se cumpla cierta condicion para dar comienzo a la ejecucion del resto de las tareas del job. Esas condiciones por lo general son transacciones o eventos que ocurren en el Blockchanin. Chainlink ya ofrece algunas implementaciones que podes reutilizar cuando configuras un job en un nodo. Tambien podes crear tu propia tarea de arranque si asi lo precisas.

Estas tareas de arranque son las que determinan el modelo push o pull del Oraculo. Las tareas que vigilan el transaction log del Blockchain por transacciones o eventos, soportan el modelo pull. Por el contrario, tambien tenes tareas que se ejecutan en intervalos de tiempo predeterminados y continuan con otras tareas que actualizan el estado de un smart contract. Estas ultimas son para soportar el modelo push.

Una vez que la tarea de arranque se ejecuto, esta devuelve datos que se pasan al resto de las tareas que se ejecutan a continuacion. La ultima tarea en ejecutarse puede llamar a un sistema externo o bien enviar los datos resultantes al Blockchain.

Esto es un ejemplo de un job,

{
  "name": "Integracion Web",
  "initiators": [
    {
      "type": "web"
      }
    }
  ],
  "tasks": [
    {
      "type": "myadapter"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

La tarea de arranque "web", es una de las tareas predefinidas por Chainlink y permite arrancar el job desde una interface web que provee el nodo. Una vez que este job arranca, ejecuta otra tarea que se llama "myadapter" y que probablemente envie datos a un sistema externo.

Como podes ver, los job implementan el patron de Tuberias o Pipeline, en donde tenes datos de ingreso que se van pasando entre las distintas tareas para luego convertirlos en un resultado final.

Un nodo nos da dos interfaces para configurar jobs y adapters (se explica a continuacion), por linea de comando con un tool, o por una interface web. Ambos necesitan de un usuario y contrasena que se registran cuando el nodo se configura por primera vez.

Adaptadores o Adapters

Un adaptador o external adapter es un componente para integrar Chainlink con sistemas externos.

Un adaptador no es otra cosa que una API que sigue ciertas convenciones para los parametros de entrada y lo de salida. El desarrollador escribe esta API y la puede publicar como un adaptador en un nodo de Chainlink. Se registra especificando la URL en donde esta hosteada. Una vez que se registro en el nodo, se la puede referenciar desde un job.

La API de un adaptador solo puede recibir HTTP POSTs con el siguiente JSON,

{"data":{}, "meta": {}, "id": "<job id>", "responseURL": "<url>"}
Enter fullscreen mode Exit fullscreen mode
  • data: Son los datos de ingreso que la API necesita para pasarle al sistema externo
  • meta: Opcional. Son argumentos de configuracion.
  • responseURL: Opcional. Si la API tiene que devolver una respuesta con un callback a esta URL (para llamadas asyncronicas)
  • id: Opcional. El identificador del job.

La respuesta de un adaptador debe ser la siguiente:

{"data": {}, "error": {}, "pending": true|false}
Enter fullscreen mode Exit fullscreen mode
  • data: Un objeto que representa la respuesta de la llamada externa.
  • error: Opcional. Detalles de error si la llamada fallo.
  • pending: Opcional. Para llamadas asincronicas, nos indica si la llamada esta pendiente de esperar una respuesta.

Un adaptador no devuelve codigos de estado HTTP para especificar si la llamada fallo o no. Y si el sistema externo necesita credenciales de autenticacion, se le deben pasar al adaptador como parte de los datos de entrada, o se deben configurar en el nodo.

Al momento de escribir este post, el nodo no pasa ningun token de autenticacion al adapter cuando lo llama. Si el adapter corre como una API en un servidor externo al nodo, y queres restringir quien puede hacer una llamada al mismo, vas a tener que restringer las llamadas por IP en el subnet en donde corren los nodos.

Correr un nodo de Chainlink

Cualquiera puede correr un nodo de Chainlink bajandose el codigo fuente o a traves de una imagen de Docker.

Este post solo va a discutir como hacerlo con Docker. El contenedor de Docker va a necesitar de los siguientes requisitos.

1- Una base de datos Postgres. (Tambien se puede correr como otro contenedor de Docker)
2- Acceso a un nodo de Ethereum, ya sea un nodo propio o un nodo publico en Infura.

Para este ejemplo voy a mostrar como correr la base de datos Posgres tambien como un contenedor de Docker.

El primer paso es crear una red en Docker para que nodo y la base de datos pueden comunicarse entre si.

docker network create chainlink-net
Enter fullscreen mode Exit fullscreen mode

El segundo paso es correr el contenedor de Postgres

docker run -d -p 5432:5432 --name chainlink-db --net=chainlink-net -e POSTGRES_PASSWORD=password postgres
Enter fullscreen mode Exit fullscreen mode

El tercer paso es crear un archivo con la configuracion del nodo de Chainlink (Este nodo va a utilizar Rinkeby). El archivo se debe llamar .env

LOG_LEVEL=debug
ETH_CHAIN_ID=4
MIN_OUTGOING_CONFIRMATIONS=2
LINK_CONTRACT_ADDRESS=0x01BE23585060835E02B77ef475b0Cc51aA1e0709
CHAINLINK_TLS_PORT=0
SECURE_COOKIES=false
GAS_UPDATER_ENABLED=true
ALLOW_ORIGINS=*
ETH_URL=<YOUR INFURA Rinkeby ETH URL>
DATABASE_URL=postgresql://postgres:password@chainlink-db:5432/postgres?sslmode=disable
Enter fullscreen mode Exit fullscreen mode

Finalmente, se necesita ejecutar este comando arrancar el nodo de Chainlink

docker run -v ~/.chainlink-rinkeby:/chainlink -p 6688:6688 -it --net=chainlink-net --env-file=.env smartcontract/chainlink:0.10.8 local n
Enter fullscreen mode Exit fullscreen mode

Una vez que el nodo esta corriendo, tambien ofrece acceso a un portal de administracion. Si lo corren en forma local, esta disponible en el puerto 6688 por defecto. Pueden navegar a https://localhost:6688 para comenzar a configurar jobs y adapters.

Si queres asociarle fondos en ETH a la clave privada del nodo, podes usar el tool por linea de comando para exportarla y luego importarla en un wallet externo. Necesitas correr estos comandos,

docker exec -it <container> bash
chainlink admin login
chainlink keys eth list
chainlink keys eth export <node-address> -p .password --output key.json
Enter fullscreen mode Exit fullscreen mode

Node-Address es la direccion publica del nodo, esta se muestra una vez que arrancas al mismo o en la interface web. Una vez que corren este comando, van a obtener la clave privada en un archivo json. Pueden importar el mismo directamente en un wallet como Metamask.

Discussion (0)