En Linux y Blockchains – Cartesi

Introducción

Tómese un momento para contemplar la complejidad de la infraestructura de software que impregna cada vez más todos los aspectos de nuestras vidas. Se trata de sistemas operativos, bibliotecas de software, herramientas, protocolos, lenguajes de programación, compiladores y otras tecnologías. Este entorno es el resultado de un esfuerzo global continuo durante los últimos 50 años y ha consumido miles de millones de horas de trabajo. Es esta red de componentes interdependientes la que permitió que el software se generalizara. Sin él, ninguno de los servicios y aplicaciones en los que hemos llegado a confiar habría sido posible, ni siquiera concebible.

Las blockchains son un avance comparativamente reciente. La innovación clave de Bitcoin fue un mecanismo a través del cual una red de agentes puede mantener un consenso descentralizado sobre un estado compartido. En este contexto, la descentralización significa que los propios participantes mantienen el estado de una manera que no requiere confianza mutua. Este estado contiene, entre otros datos, un sistema de pago. La participación que cada participante tiene en la economía resultante funciona como un incentivo para hacer que este estado esté ampliamente disponible y para rechazar cambios no válidos en el estado. Este ciclo virtuoso hace que el sistema sea autosuficiente: el sistema de pago se construye sobre el consenso descentralizado, que solo funciona debido a los incentivos creados por el propio sistema de pago.

Ethereum generalizó significativamente esta idea al permitir que las transacciones se expresen como programas arbitrarios o contratos inteligentes. Pronto se hizo evidente que las transacciones programables en un estado descentralizado podían usarse para mucho más que simplemente mantener un sistema de pago. Las blockchains se convirtieron esencialmente en equitativas y descentralizadas "computadoras del mundo" que no pueden apagarse y no pueden ser controladas por individuos o instituciones. Surgió un nuevo tipo de aplicación (descentralizada), llamada DApp, que se ejecuta en estas computadoras del mundo.

En comparación con los programas informáticos tradicionales, las DApps se enfrentan a dos limitaciones principales. El primero es uno es la escalabilidad. Debido a que los contratos inteligentes deben ser ejecutados por todos los participantes en una cadena de bloques, los DApp están paralizados por estrictos límites en el cálculo, tasas de transacción lentas, espacio de almacenamiento reducido y precio elevado. Este problema ha sido ampliamente reconocido como uno de los factores clave que limitan el crecimiento de la adopción de . Como resultado, varios proyectos actuales se centran en el desarrollo de soluciones de escalabilidad para cadenas de bloques (por ejemplo, plasma, fragmentación, cadenas laterales, canales estatales, etc.).

La segunda limitación ha recibido mucha menos atención: la infraestructura de software primitiva. Aquí, el culpable es la falta de un sistema operativo. Los sistemas operativos son la base sobre la cual se construyen los últimos 50 años de desarrollo de software. Cortado de todo este trabajo anterior, los desarrolladores de DApp luchan para realizar tareas que son triviales para los desarrolladores convencionales, como transferir archivos, comprimir datos, encontrar el color de un píxel en una imagen o consultar una base de datos para un registro. Incluso falta el concepto de un archivo en sí!

Existe un abismo entre el software de inmaduro de hoy y la vasta infraestructura de software que está disponible y que se ejecuta en nuestras computadoras portátiles y teléfonos inteligentes.

Los DApps deben ser capaces de realizar cálculos como los que realizan las aplicaciones "centralizadas" con regularidad. El desarrollo de DApp debería tener acceso a los idiomas, bibliotecas y herramientas que son estándar en los sistemas operativos modernos como Linux. Yendo aún más lejos, debemos esforzarnos por lograr una infraestructura de nivel superior que sea genérica y escalable al tiempo que abstraemos las tuercas y los pernos de las cadenas de bloques individuales y las capas de consenso. Los desarrolladores deberían poder concentrarse en su lógica DApp específica en lugar de lidiar con las complejidades de los canales estatales, las cadenas laterales y la propia cadena de bloques. Las DApps deben ser fácilmente transportables a través de diferentes blockchains.

Este tipo de infraestructura desdibujaría las líneas entre las habilidades requeridas para desarrollar aplicaciones centralizadas y descentralizadas. Allanaría el camino para una nueva generación de aplicaciones DApp que hoy son tan inconcebibles como lo era la Internet moderna hace 50 años. En Cartesi hemos estado persiguiendo este inevitable futuro. Para ese fin, especificamos e implementamos una infraestructura de Linux descentralizada para aplicaciones de escalables.

Antes de adentrarnos en la maleza de nuestro proyecto, veamos brevemente los conceptos básicos de los sistemas de capa 2 para DApp escalables.. Los sistemas como Plasma, canales estatales, TrueBit y Cartesi difieren entre sí en muchos aspectos, pero se basan en los mismos conceptos fundamentales.

Soluciones Layer-2

Las cadenas de bloques logran el consenso mediante la redundancia, replicando la computación y los datos en toda la red. Debido a eso, las DApps no pueden confiar en ellas para transacciones de alta frecuencia, para procesos complejos o para almacenar grandes cantidades de datos. Esto sería costoso, derrochador e ineficiente. El rango de las aplicaciones prácticas está fuertemente restringido por estas limitaciones. En contraste, las aplicaciones centralizadas que se ejecutan en servidores en la nube (o incluso en nuestros dispositivos personales) no sufren estas limitaciones. Lo que necesitamos es combinar el rendimiento y la generalidad de los sistemas de software convencionales con el consenso y las garantías de seguridad de blockchains.

Aunque el consenso global es un recurso costoso, la mayoría de los datos y el procesamiento asociados con una aplicación de datos (es decir, aparte de los aspectos financieros) no son de interés para toda la red. Solo son importantes para las pocas partes involucradas en esa aplicación específica. Debido a esto, casi siempre es suficiente para que las partes involucradas mantengan su propio consenso local. Las sólidas garantías ofrecidas por el consenso global de toda la red de se pueden usar con moderación para resolver eventuales disputas entre estas partes.

La idea general es la siguiente. Todas las partes involucradas con un DApp dado están ligadas por contratos inteligentes con incentivos criptoeconómicos bien definidos que recompensan el comportamiento honesto y castigan la falta de honradez. Un diseño común es que los contratos inteligentes requieran que todas las partes involucradas hagan un depósito como garantía antes de comprometerse con el DApp. Cuando todos los participantes están de acuerdo con un cambio en el estado local de DApp, comunican su acuerdo y conjunto de cambios a la cadena de bloques. La cadena de bloques reacciona modificando el estado global relevante. Cuando cualquier parte involucrada tiene pruebas de mala conducta, puede apelar a la cadena de bloques antes de que los cambios se vuelvan permanentes.

El se convierte en un árbitro que arbitra a favor de la parte honesta, recompensándolo con la garantía incautada del mal actor.

Esta idea simple pero poderosa minimiza el consumo de recursos de al tiempo que conserva las sólidas garantías de seguridad de toda la red. Este mecanismo de arbitraje está inspirado en las antiguas interacciones entre humanos. No involucramos a la corte suprema antes de cada interacción humana. La gran mayoría de las transacciones, incluso aquellas que involucran dinero, se resuelven localmente. No llamamos a un abogado antes de salir a comprar frutas en un mercado callejero. Eso sería extremadamente ineficiente. En su lugar, tenemos un sistema que se usa solo cuando es necesario: el sistema judicial solo está involucrado en caso de disputas legales.

La aplicación de esta metáfora a los sistemas de cadena de bloques bien diseñados que involucran incentivos económicos criptográficos es la clave para DApps escalables y eficientes.

Cartesi: Linux en el

Acabamos de ver cómo un sistema de capa 2 puede desacoplar las interacciones locales de la cadena de bloques al tiempo que conserva sus garantías de seguridad. Ahora podemos usar este desacoplamiento para aumentar significativamente la expresividad y el poder de la infraestructura. En particular, creamos un cambio de paradigma en el desarrollo de DApp al transformar la plataforma de lo que se siente como una hoja de cálculo de juguete en algo que se comporta como una computadora real que ejecuta Linux.

Figura 1. La arquitectura del núcleo de Cartesi.

El núcleo de Cartesi (ver figura 1) es un conjunto de tecnologías básicas que constituyen el primer paso hacia la visión que hemos estado discutiendo. Incluye componentes en cadena y fuera de cadena. El componente fuera de cadena es lo que llamamos el Nodo Cartesi. En pocas palabras, cada participante que quiera interactuar con un DApp Cartesi lo hace a través de un Nodo Cartesi. Pueden ejecutar su propio nodo Cartesi o contratar a un tercero que represente sus intereses.

El módulo esencial en el nodo Cartesi es la máquina Cartesi, una máquina virtual personalizada que emula un microprocesador RISC-V y ejecuta una distribución de Linux incorporada. Al desarrollar un DApp con Cartesi, la mayoría de la lógica descentralizada se codificará para ejecutarse bajo Linux fuera de cadena, en lugar de codificarse como contratos inteligentes y se implementará en la cadena.

Maquinas cartesi

Las máquinas Cartesi son especiales en muchos sentidos. Primero, son completamente independientes. Esto significa que no hay fuentes externas de entropía que puedan alterar el estado de la máquina de una manera no determinista (como un teclado, un mouse o un reloj de pared). En segundo lugar, son reproducibles. En otras palabras, cuando dos máquinas Cartesi comienzan desde el mismo estado inicial y se ejecutan durante el mismo número de ciclos de procesador, alcanzan exactamente el mismo estado final. Esto es cierto independientemente de la arquitectura y el sistema operativo que aloja el nodo Cartesi. Finalmente, las máquinas Cartesi ofrecen total transparencia. El estado se especifica y expone de tal manera que cualquier observador externo con acceso a todo el estado en un ciclo del procesador determinado puede predecir el estado completo en el siguiente ciclo del procesador.

Las propiedades de autocontención y reproducibilidad aseguran que cualquiera de las dos partes que tienen acceso al estado inicial de una Máquina Cartesi obtendrán los mismos resultados cuando ejecuten la máquina en sus Nodos Cartesi. Naturalmente, esto es vital para el consenso. Desafortunadamente, en general no está garantizado por arquitecturas de hardware o máquinas virtuales. La Máquina Cartesi fue diseñada específicamente para satisfacer estos requisitos. La propiedad de transparencia significa que todo el estado de una Máquina Cartesi puede ser Merklized. Entre otras cosas, esto permite que la cadena de bloques represente una máquina con un solo hash. Como veremos, estas propiedades permiten que resuelva de manera eficiente cualquier disputa sobre los resultados de la ejecución de Cartesi Machines fuera de la cadena.

La representación de la máquina

Figura 2. Vistas fuera de cadena y en cadena de una Máquina Cartesi.

Fuera de cadena, la máquina Cartesi está representada explícitamente (ver figura 2, izquierda). Sus componentes principales son su memoria y un surtido de unidades. En una configuración típica, el kernel de Linux se carga en la memoria, y la unidad 1 contiene un sistema de archivos con una distribución de Linux incorporada. La distribución se puede configurar para arrancar y ejecutar cualquier programa en este sistema de archivos. Un programa hipotético podría procesar la entrada encontrada en la unidad 2 y escribir los resultados en la unidad 3. Desde el exterior, las unidades son simplemente archivos que residen en el Nodo Cartesi. La Máquina Cartesi los expone al kernel de Linux como dispositivos. Desde el punto de vista de los programas que se ejecutan en Linux, se pueden montar como sistemas de archivos normales y pueden contener múltiples directorios y archivos. La ejecución de la Máquina Cartesi producirá un archivo de salida en el Nodo Cartersi que contiene otro sistema de archivos, y dentro de este sistema de archivos se encuentran los resultados deseados del cálculo.

En la cadena, la Máquina Cartesi está representada por el hash de la raíz del árbol Merkle de todo su estado (ver figura 2, derecha). Este estado incluye la memoria y las unidades, pero también todo lo necesario para el funcionamiento de la Máquina Cartesi (como los valores de todos los registros y dispositivos). Los hash de raíz de árbol Merkle son especiales porque admiten dos operaciones importantes. Primero, es posible verificar o rechazar cualquier reclamo sobre el valor de cualquier parte del estado. En segundo lugar, es posible obtener el nuevo hash de raíz del árbol Merkle correspondiente a cualquier modificación del estado. Estas operaciones se pueden realizar de manera muy eficiente dentro de la cadena de bloques. Los contratos inteligentes pueden, por ejemplo, reemplazar una unidad completa en una Máquina Cartesi y obtener el nuevo hash de raíz correspondiente. A la inversa, dado el hash raíz final para una Máquina Cartesi y el hash de una unidad de salida, los contratos inteligentes pueden verificar que la unidad realmente pertenece a esa máquina.

Solución de controversias

Considere dos actores, Alice y Bob, ambos involucrados en una transacción controlada por un contrato inteligente. Supongamos que la transacción implica algún cálculo complejo que no es práctico ejecutar en cadena. Ahora suponga además que el contrato inteligente conoce el hash raíz inicial para una Máquina Cartesi que, cuando se inicia, ejecuta un programa en la unidad 1 que realiza el cálculo requerido utilizando la entrada de la unidad 2 y escribe la salida en la unidad 3. Utilizando operaciones hash eficientes , el contrato inteligente puede reemplazar la unidad 2 con su entrada deseada. Luego, puede exigir a Bob el hash de raíz que resulta de ejecutar la correspondiente máquina Cartesi fuera de cadena.

Ahora hay dos posibilidades. Si Alice está de acuerdo con Bob, el contrato inteligente puede proceder solicitando a Bob detalles sobre la unidad 2, convencido de que Alice y Bob estarán de acuerdo con las consecuencias. Si Alice no está de acuerdo, comienza una disputa depositando una garantía. Si Bobs quiere defenderse de la disputa, responde depositando la misma garantía. (De lo contrario, después de un tiempo muerto, se considera que ha perdido el derecho). Lo que sigue es un protocolo interactivo, que involucra a Alice y Bob y está mediado por la cadena de bloques, que garantiza que quien sea honesto ganará la disputa.

El juego de verificación (Feige y Kilian 1997) es un algoritmo que permite que un árbitro con recursos computacionales limitados medie un juego entre dos jugadores computacionalmente ilimitados. En nuestro caso, el mediador limitado es un conjunto de contratos inteligentes que se ejecutan en la cadena de bloques. Los jugadores ilimitados son las Máquinas Cartesi que se ejecutan en los Nodos Cartesi de Alice y Bob. TrueBit también utiliza este procedimiento, y puede encontrar una explicación detallada en este gran artículo de Sina Habibian.

En pocas palabras, utilizando una búsqueda n-aria, un contrato inteligente identifica el último ciclo del procesador para el cual Alice y Bob acuerdan el hash de raíz para todo el estado de la Máquina Cartesi. Luego, el ejecuta una sola instrucción RISC-V para obtener el hash raíz para el estado que sigue. Se sabe que Alice y Bob no están de acuerdo con este hash. Al identificar quién publicó los resultados correctos, el contrato inteligente puede arbitrar a favor de la parte honesta y recompensarlo con ambas garantías.

Ejecutar una sola instrucción RISC-V es indoloro y muy rentable para la cadena de bloques. La localización de la instrucción toma solo tiempo y espacio logarítmicos. Además, este proceso solo se realiza en caso de que surja una disputa. Las disputas son extremadamente raras, porque el engaño siempre será atrapado, y el engaño trae castigo.

Un ejemplo completo: Juegos por turnos

Como ejemplo concreto, mostraremos cómo Cartesi Core puede simplificar enormemente el trabajo de un desarrollador de DApp implementando un juego por turnos, como Go o Chess. Alice y Bob jugarán por dinero, el ganador se lleva todo. Los jugadores están representados en el juego por los componentes DApp que se ejecutan dentro de sus Nodos Cartesi. Comienzan un nuevo juego depositando el valor de sus apuestas en un contrato inteligente. Después de esto, el juego continúa casi completamente fuera de la cadena.

Alice y Bob mantienen toda la secuencia de movimientos Merklized fuera de cadena. Llamemos al hash raíz de este árbol el hash de secuencia. Cuando es el turno de Alicia para hacer un movimiento, lo agrega a la secuencia, obtiene un nuevo hash de secuencia y lo firma. A continuación, envía el movimiento, el hash de secuencia y la firma a Bob mediante un canal de estado. Bob valida el movimiento de Alice, lo agrega a su copia de la secuencia de movimiento, calcula el hash de la secuencia, confirma que coincide con el de Alice y luego verifica su firma. Si todo sale bien, ahora es su turno. El juego continúa de esta manera hasta que suceda una de estas dos cosas: dejan de jugar el juego de manera prematura, o uno de ellos finalmente gana el juego.

Supongamos que Bob quiere reclamar la victoria. Publica el hash de la secuencia de Alice, su firma y su movimiento ganador a la cadena de bloques. Un contrato inteligente primero verifica la firma de Alice en el hash de secuencia. Luego, delega la decisión de quién ganó en una Máquina Cartesi de "fin de juego" (que se ejecuta inicialmente en el propio nodo de Bob, como veremos en breve). Esta es una máquina que, dada una secuencia de movimientos en la unidad 2 y un movimiento final en la unidad 3, se detiene con un código de salida exitoso si el movimiento gana el juego, o con una falla, si no lo hace. El software que se ejecuta dentro de esta Máquina Cartesi fue escrito por el desarrollador en el lenguaje de programación de su elección. Es gratis aprovechar todas las instalaciones modernas y el software de código abierto disponible dentro de un sistema operativo Linux que se ejecuta sin ninguna limitación de recursos artificiales en una máquina RISC-V autónoma.

Para definir el estado inicial de la máquina del final del juego, el contrato inteligente utiliza operaciones hash para reemplazar la unidad 2 con la secuencia de movimientos proporcionada por Alice y para reemplazar la unidad 3 con la jugada final de Bob. Exige que Bob haga funcionar la máquina correspondiente fuera de cadena y publique el hash de la raíz Merkle-tree de su estado final en el . Si Bob está diciendo la verdad, podrá defenderse contra cualquier desafío potencial de Alicia con respecto al valor de este hash. Bob también podrá demostrar a la cadena de bloques que la máquina del final del juego se detuvo a su favor al mostrar que la palabra designada como el código de salida en su memoria tiene el valor apropiado. Sin embargo, si Bob está mintiendo, Alice disputará su hash final y ganará el siguiente juego de verificación.

Un problema interesante ocurre cuando los jugadores dejan de colaborar prematuramente. Tal vez sea el turno de Bob y, dándose cuenta de que su posición es desesperada, se niega a enviar su movimiento a Alice. Por sí sola, la cadena de bloques no tiene forma de saber si esto realmente está sucediendo, o si Alicia es la que ignora los intentos de contacto de Bob a través del canal estatal. Afortunadamente, hay formas de resolver este problema de disponibilidad de datos. Una solución simple es la siguiente. Frustrada por el comportamiento de Bob, Alice informa a la cadena de bloques de su negativa a cooperar. Para hacerlo, envía el último hash de secuencia de Bob y su firma. La cadena de bloques ofrece a Bob la posibilidad de enviar un hash de secuencia aún más reciente firmado por Alice. Ahora se requiere que ambos jugadores envíen movimientos futuros a través de la cadena de bloques.

De ahora en adelante, todo lo que debe hacer el es controlar de quién es el turno, aceptar un nuevo movimiento del jugador correcto y usar las operaciones de hash para mantener la secuencia actualizada. Si uno de los jugadores deja de publicar movimientos, el otro puede reclamar un tiempo de espera y ganar la apuesta. Si uno de los jugadores reclama la victoria, el tiene toda la información necesaria para construir la máquina del final del juego como antes: problema resuelto.

Ventajas de este diseño

Las ventajas de este diseño son que toda la complejidad, el procesamiento y el almacenamiento de datos asociados con el juego suceden fuera de la cadena de bloques. Parte de ella se ejecuta en el Nodo Cartesi, y parte en la Máquina Cartesi. Ambos sistemas ejecutan Linux, donde los desarrolladores son más productivos. En el escenario típico donde los jugadores cooperan, el simplemente acepta las apuestas cuando comienza un juego y las transfiere al ganador cuando termina. Cuando los jugadores dejan de cooperar, la cadena de bloques todavía tiene muy poco trabajo por hacer: Mantiene solo la secuencia hash actualizada. Nunca almacena la secuencia de movimientos, nunca necesita acceso al estado del juego, o incluso se preocupa por sus reglas. Incluso cuando surge una disputa, se resuelve automáticamente mediante el núcleo de Cartesi.

Considere las ganancias en productividad que un diseño como este aporta al desarrollo de y la mayor variedad de aplicaciones que permite esta escalabilidad adicional. Sólo podemos empezar a imaginar.

El futuro

En los últimos 20 meses, la mayor parte del Cartesi Core, tal como se describe en nuestro documento técnico, se ha implementado. En futuros artículos, mostraremos su poder y flexibilidad construyendo ejemplos de DApps. No hace falta decir que estas DApps involucrarán cálculos verificables sobre grandes cantidades de datos, al tiempo que aprovecharán la amplia infraestructura de software disponible para los desarrolladores en Linux.

El núcleo de Cartesi es solo el primer paso hacia nuestra visión. La misión de Cartesi es cerrar la brecha entre las aplicaciones centralizadas y descentralizadas, tanto en términos de posibilidad como de conveniencia.

Seguiremos trabajando para eliminar todas las limitaciones de DApps con tecnología de Cartesi. Ofreceremos canales de estado sin problemas y un protocolo de intercambio de datos verificable fuera de la cadena. Crearemos un nuevo entorno de programación que integre el desarrollo de todos los componentes de un DApp Cartesi. En última instancia, haremos que las DApps sean fácilmente portátiles a través de diferentes blockchains.

Nuestra esperanza es que, al empoderar a los desarrolladores de DApp, los ayudemos a construir productos que sean cada vez más atractivos para los usuarios y nos acerquemos a un futuro en el que la descentralización sea menos onerosa.