Enfrentamiento de contrato inteligente: Hyperledger Fabric vs MultiChain vs Ethereum vs Corda

Nodo de origen: 1585333

Hay más de una forma de poner código en una cadena de bloques

En la mayoría de las discusiones sobre blockchains, no pasa mucho tiempo para que surja la noción de "contratos inteligentes". En la imaginación popular, los contratos inteligentes automatizan la ejecución de interacciones entre partes, sin necesidad de un intermediario confiable. Al expresar las relaciones legales en código en lugar de palabras, prometen permitir que las transacciones se realicen directamente y sin error, ya sea de forma deliberada o no.

Desde un punto de vista técnico, un contrato inteligente es algo más específico: un código de computadora que vive en una cadena de bloques y define las reglas para las transacciones de esa cadena. Esta descripción suena bastante simple, pero detrás hay una gran variación en cómo se expresan, ejecutan y validan estas reglas. Al elegir una plataforma blockchain para una nueva aplicación, la pregunta "¿Esta plataforma admite contratos inteligentes?" no es el adecuado para preguntar. En cambio, debemos preguntarnos: "¿Qué tipo de contratos inteligentes admite esta plataforma?"

En este artículo, mi objetivo es examinar algunas de las principales diferencias entre los enfoques de contratos inteligentes y las compensaciones que representan. Lo haré mirando cuatro plataformas populares de blockchain empresarial que admiten algún tipo de código personalizado en cadena. Primero, los de IBM Tejido Hyperledger, que llama a sus contratos "chaincode". En segundo lugar, nuestra plataforma MultiChain, que presenta filtros inteligentes en la versión 2.0. Tercero, Ethereum (y su permiso Quórum y Madriguera spin-offs), que popularizó el nombre de "contrato inteligente". Y finalmente, R3 Corda, que hace referencia a "contratos" en sus transacciones. A pesar de toda la terminología diferente, en última instancia, todos estos se refieren a la misma cosa: código específico de la aplicación que define las reglas de una cadena.

Antes de continuar, debo advertir al lector que gran parte del contenido siguiente es de naturaleza técnica y supone cierta familiaridad con los conceptos generales de programación y bases de datos. Para bien o para mal, esto no se puede evitar: sin entrar en detalles, es imposible tomar una decisión informada sobre si usar una cadena de bloques para un proyecto en particular y (si es así) el tipo correcto de cadena de bloques para usar.

Conceptos básicos de Blockchain

Comencemos con un poco de contexto. Imagine una aplicación compartida por varias organizaciones, que se basa en una base de datos subyacente. En una arquitectura centralizada tradicional, esta base de datos está alojada y administrada por una sola parte en la que todos los participantes confían, incluso si no confían entre sí. Las transacciones que modifican la base de datos solo se inician mediante aplicaciones en los sistemas de esta parte central, a menudo en respuesta a los mensajes recibidos de los participantes. La base de datos simplemente hace lo que se le dice porque la aplicación está implícitamente confiable para enviarle solo transacciones que tengan sentido.

Las cadenas de bloques proporcionan una forma alternativa de administrar una base de datos compartida, sin un intermediario confiable. En una cadena de bloques, cada participante ejecuta un "nodo" que contiene una copia de la base de datos y procesa de forma independiente las transacciones que la modifican. Los participantes se identifican mediante claves públicas o "direcciones", cada una de las cuales tiene una clave privada correspondiente conocida solo por el propietario de la identidad. Si bien las transacciones pueden ser creadas por cualquier nodo, están "firmadas digitalmente" por la clave privada de su iniciador para demostrar su origen.

Los nodos se conectan entre sí de una manera entre pares, propagando rápidamente las transacciones y los "bloques" en los que se marcan y se confirman en toda la red. La cadena de bloques en sí es literalmente una cadena de estos bloques, que forma un registro ordenado de cada transacción histórica. Se utiliza un "algoritmo de consenso" para garantizar que todos los nodos lleguen a un acuerdo sobre el contenido de la cadena de bloques, sin requerir un control centralizado. (Tenga en cuenta que parte de esta descripción no se aplica a Corda, en el que cada nodo tiene solo una copia parcial de la base de datos y no hay una cadena de bloques global. Hablaremos más sobre eso más adelante).

En principio, cualquier aplicación de base de datos compartida se puede diseñar utilizando una cadena de bloques en su núcleo. Pero hacerlo crea una serie de desafíos técnicos que no existen en un escenario centralizado:

  • Reglas de transacción. Si algún participante puede cambiar directamente la base de datos, ¿cómo nos aseguramos de que siga las reglas de la aplicación? ¿Qué impide que un usuario corrompa los contenidos de la base de datos de una manera egoísta?
  • Determinismo. Una vez que se definen estas reglas, se aplicarán varias veces por varios nodos al procesar transacciones para su propia copia de la base de datos. ¿Cómo nos aseguramos de que cada nodo obtenga exactamente el mismo resultado?
  • Prevención de conflictos. Sin coordinación central, ¿cómo lidiamos con dos transacciones que siguen las reglas de la aplicación, pero que entran en conflicto entre sí? Los conflictos pueden provenir de un intento deliberado de jugar el sistema, o ser el resultado inocente de la mala suerte y el momento.

Entonces, ¿dónde entran los contratos inteligentes, los filtros inteligentes y el chaincode? Su propósito principal es trabajar con la infraestructura subyacente de una cadena de bloques para resolver estos desafíos. Los contratos inteligentes son el equivalente descentralizado del código de la aplicación: en lugar de ejecutarse en un lugar central, se ejecutan en múltiples nodos en la cadena de bloques, creando o validando las transacciones que modifican el contenido de esa base de datos.

Comencemos con las reglas de transacción, el primero de estos desafíos, y veamos cómo se expresan en Fabric, MultiChain, Ethereum y Corda, respectivamente.

Reglas de transacción

Las reglas de transacción realizan una función específica en las bases de datos basadas en blockchain, restringiendo transformaciones eso se puede realizar en el estado de esa base de datos. Esto es necesario porque cualquiera de sus participantes puede iniciar las transacciones de una cadena de bloques, y estos participantes no confían entre sí lo suficiente como para permitirles modificar la base de datos a voluntad.

Veamos dos ejemplos de por qué se necesitan reglas de transacción. Primero, imagine una cadena de bloques diseñada para agregar y sellar documentos PDF publicados por sus participantes. En este caso, nadie debería tener el derecho de eliminar o cambiar documentos, ya que hacerlo socavaría todo el propósito del sistema: la persistencia de los documentos. En segundo lugar, considere una cadena de bloques que representa un libro contable financiero compartido, que realiza un seguimiento de los saldos de sus usuarios. No podemos permitir que un participante infle arbitrariamente su propio saldo o quite el dinero de otros.

Entradas y salidas

Nuestras plataformas blockchain se basan en dos enfoques generales para expresar las reglas de transacción. El primero, que llamo el "modelo de entrada-salida", se utiliza en MultiChain y Corda. Aquí, las transacciones enumeran explícitamente las filas o "estados" de la base de datos que eliminan y crean, formando un conjunto de "entradas" y "salidas" respectivamente. La modificación de una fila se expresa como la operación equivalente de eliminar esa fila y crear una nueva en su lugar.

Dado que las filas de la base de datos solo se eliminan en las entradas y solo se crean en las salidas, cada entrada debe "gastar" la salida de una transacción anterior. El estado actual de la base de datos se define como el conjunto de "salidas de transacciones no gastadas" o "UTXO", es decir, salidas de transacciones anteriores que aún no se han utilizado. Las transacciones también pueden contener información adicional, llamada "metadatos", "comandos" o "archivos adjuntos", que no se convierten en parte de la base de datos, pero ayudan a definir su significado o propósito.

Dados estos tres conjuntos de entradas, salidas y metadatos, la validez de una transacción en MultiChain o Corda está definida por algún código que puede realizar cálculos arbitrarios en esos conjuntos. Este código puede validar la transacción o devolver un error con una explicación correspondiente. Puede pensar en el modelo de entrada-salida como un "inspector" automatizado que tiene una lista de verificación que garantiza que las transacciones sigan todas y cada una de las reglas. Si la transacción falla en cualquiera de esas comprobaciones, todos los nodos de la red la rechazarán automáticamente.

Cabe señalar que, a pesar de compartir el modelo de entrada-salida, MultiChain y Corda lo implementan de manera muy diferente. En MultiChain, las salidas pueden contener activos y / o datos en formato JSON, texto o binario. Las reglas se definen en "filtros de transacción" o "filtros de flujo", que se pueden configurar para verificar todas las transacciones, o solo aquellas que involucran activos particulares o agrupaciones de datos. Por el contrario, un "estado" de salida de Corda está representado por un objeto en el lenguaje de programación Java o Kotlin, con campos de datos definidos. Las reglas de Corda se definen en "contratos" que se adjuntan a estados específicos, y el contrato de un estado solo se aplica a transacciones que contienen ese estado en sus entradas o salidas. Esto se relaciona con el de Corda modelo de visibilidad inusual, en el que las transacciones solo pueden ser vistas por sus contrapartes o aquellas cuyas transacciones posteriores afectan.

Contratos y mensajes

El segundo enfoque, que llamo el "modelo de mensaje de contrato", se usa en Hyperledger Fabric y Ethereum. Aquí, se pueden crear múltiples "contratos inteligentes" o "chaincodes" en la cadena de bloques, y cada uno tiene su propia base de datos y código asociado. La base de datos de un contrato solo puede modificarse mediante su código, en lugar de hacerlo directamente mediante transacciones de blockchain. Este patrón de diseño es similar a la "encapsulación" de código y datos en la programación orientada a objetos.

Con este modelo, una transacción de blockchain comienza como un mensaje enviado a un contrato, con algunos parámetros o datos opcionales. El código del contrato se ejecuta en reacción al mensaje y los parámetros, y es libre de leer y escribir su propia base de datos como parte de esa reacción. Los contratos también pueden enviar mensajes a otros contratos, pero no pueden acceder a las bases de datos de cada uno directamente. En el lenguaje de las bases de datos relacionales, los contratos actúan como forzado "Procedimientos almacenados", donde todo el acceso a la base de datos se realiza a través de algún código predefinido.

Tanto Fabric como Quorum, una variación de Ethereum, complican esta imagen al permitir que una red defina múltiples "canales" o "estados privados". El objetivo es mitigar el problema de la confidencialidad de blockchain creando entornos separados, cada uno de los cuales solo es visible para un subgrupo particular de participantes. Si bien esto suena prometedor en teoría, en realidad los contratos y los datos en cada canal o estado privado están aislados de los de los demás. Como resultado, en términos de contratos inteligentes, estos entornos son equivalentes a blockchains separados.

Reglas de ejemplo

Veamos cómo implementar las reglas de transacción para un libro mayor de un solo activo con estos dos modelos. Cada fila en la base de datos de nuestro libro mayor tiene dos columnas, que contienen la dirección del propietario y la cantidad del activo que posee. En el modelo de entrada-salida, las transacciones deben cumplir dos condiciones:

  1. La cantidad total de activos en los resultados de una transacción tiene que coincidir con el total en sus entradas. Esto evita que los usuarios creen o eliminen dinero arbitrariamente.
  2. Cada transacción debe ser firmada por el propietario de cada una de sus entradas. Esto evita que los usuarios gasten el dinero de los demás sin permiso.

En conjunto, estas dos condiciones son todo lo que se necesita para crear un sistema financiero simple pero viable.

En el modelo de contrato-mensaje, el contrato del activo admite un mensaje de "envío de pago", que toma tres parámetros: la dirección del remitente, la dirección del destinatario y la cantidad a enviar. En respuesta, el contrato ejecuta los siguientes cuatro pasos:

  1. Verifique que la transacción haya sido firmada por el remitente.
  2. Verifique que el remitente tenga fondos suficientes.
  3. Deduzca la cantidad solicitada de la fila del remitente.
  4. Agregue esa cantidad a la fila del destinatario.

Si alguno de los controles en los dos primeros pasos falla, el contrato se cancelará y no se realizará ningún pago.

Por lo tanto, los modelos de entrada-salida y mensaje-contrato son formas efectivas de definir reglas de transacción y mantener segura una base de datos compartida. De hecho, en un nivel teórico, cada uno de estos modelos puede usarse para simular al otro. Sin embargo, en la práctica, el modelo más apropiado dependerá de la aplicación que se esté creando. ¿Cada transacción afecta pocos o muchos datos? ¿Necesitamos poder garantizar la independencia de la transacción? ¿Cada pieza de datos tiene un propietario claro o hay algún estado global para compartir?

Está más allá de nuestro alcance aquí explorar cómo las respuestas deberían influir en una elección entre estos dos modelos. Pero como pauta general, al desarrollar una nueva aplicación blockchain, vale la pena tratar de expresar sus reglas de transacción en ambas formas, y ver cuál se ajusta más naturalmente. La diferencia se expresará en términos de: (a) facilidad de programación, (b) requisitos de almacenamiento y rendimiento, y (c) velocidad de detección de conflictos. Hablaremos más sobre este último tema más adelante.

Reglas incorporadas

Cuando se trata de reglas de transacción, hay una forma en que MultiChain difiere específicamente de Fabric, Ethereum y Corda. A diferencia de estas otras plataformas, MultiChain tiene varias abstracciones integradas que proporcionan algunos bloques de construcción básicos para aplicaciones basadas en blockchain, sin Requiriendo desarrolladores para escribir su propio código. Estas abstracciones cubren tres áreas que comúnmente se necesitan: (a) permisos dinámicos, (b) activos transferibles y (c) almacenamiento de datos.

Por ejemplo, MultiChain administra los permisos para conectarse a la red, enviar y recibir transacciones, crear activos o transmisiones o controlar los permisos de otros usuarios. Se pueden emitir, transferir, retirar o intercambiar múltiples activos fungibles de forma segura y atómica. Se puede crear cualquier cantidad de "secuencias" en una cadena, para publicar, indexar y recuperar datos dentro o fuera de la cadena en formato JSON, texto o binario. Todas las reglas de transacción para estas abstracciones están disponibles de forma inmediata.

Al desarrollar una aplicación en MultiChain, es posible ignorar esta funcionalidad incorporada y expresar reglas de transacción utilizando solo filtros inteligentes. Sin embargo, los filtros inteligentes están diseñados para funcionar junto con sus abstracciones incorporadas, permitiendo que su comportamiento predeterminado sea límite de manera personalizada. Por ejemplo, el permiso para ciertas actividades puede ser controlado por administradores específicos, en lugar del comportamiento predeterminado que hará cualquier administrador. La transferencia de ciertos activos puede estar limitada por el tiempo o requerir una aprobación adicional por encima de cierta cantidad. Los datos en una secuencia en particular se pueden validar para garantizar que consta solo de estructuras JSON con los campos y valores requeridos.

En todos estos casos, los filtros inteligentes crean requisitos adicionales para que las transacciones se validen, pero no remove las reglas simples que se integran. Esto puede ayudar a abordar uno de los desafíos clave en las aplicaciones blockchain: el hecho de que un error en algún código en la cadena puede tener consecuencias desastrosas. Hemos visto un sinfín de ejemplos de este problema en la cadena de bloques pública Ethereum, más famosa en el Fallecimiento del DAO y del Errores de paridad de firmas múltiples. Encuestas más amplias han encontrado una gran cantidad de vulnerabilidades comunes en los contratos inteligentes de Ethereum que permiten a los atacantes robar o congelar los fondos de otras personas.

Por supuesto, los filtros inteligentes MultiChain también pueden contener errores, pero sus consecuencias tienen un alcance más limitado. Por ejemplo, las reglas de activos incorporadas evitan que un usuario gaste el dinero de otro o que accidentalmente haga desaparecer su propio dinero, sin importar qué otra lógica contenga un filtro inteligente. Si se encuentra un error en un filtro inteligente, se puede desactivar y reemplazar con una versión corregida, mientras se protege la integridad básica del libro mayor. Filosóficamente, MultiChain está más cerca de las arquitecturas de bases de datos tradicionales, donde la plataforma de la base de datos proporciona una serie de abstracciones integradas, como columnas, tablas, índices y restricciones. Los desarrolladores de aplicaciones pueden codificar opcionalmente funciones más potentes, como disparadores y procedimientos almacenados, en los casos en que realmente se necesiten.

Reglas de transacción Telas MultiChain Ethereum Cuerda
Modelo Mensaje de contrato De entrada y salida Mensaje de contrato De entrada y salida
Empotrados Ninguna Permisos +
activos + corrientes
Ninguna Ninguna

Determinismo

Pasemos a la siguiente parte de nuestro enfrentamiento. No importa qué enfoque elijamos, las reglas de transacción personalizadas de una aplicación blockchain se expresan como código de computadora escrito por desarrolladores de aplicaciones. Y a diferencia de las aplicaciones centralizadas, este código se ejecutará más de una vez y en más de un lugar para cada transacción. Esto se debe a que varios nodos de blockchain que pertenecen a diferentes participantes tienen que verificar y / o ejecutar esa transacción por sí mismos.

Esta ejecución repetida y redundante del código introduce un nuevo requisito que rara vez se encuentra en las aplicaciones centralizadas: el determinismo. En el contexto de la computación, el determinismo significa que un código siempre dará la misma respuesta para los mismos parámetros, sin importar dónde y cuándo se ejecute. Esto es absolutamente crucial para el código que interactúa con una cadena de bloques porque, sin determinismo, el consenso entre los nodos de esa cadena puede romperse catastróficamente.

Veamos cómo se ve esto en la práctica, primero en el modelo de entrada-salida. Si dos nodos tienen una opinión diferente sobre si una transacción es válida, uno aceptará un bloque que contenga esa transacción y el otro no. Dado que cada bloque se vincula explícitamente a un bloque anterior, esto creará una "bifurcación" permanente en la red, con uno o más nodos que no aceptarán la opinión mayoritaria sobre el contenido de la cadena de bloques completa a partir de ese momento. Los nodos de la minoría quedarán desconectados del estado de evolución de la base de datos y ya no podrán usar la aplicación de manera efectiva.

Ahora veamos qué sucede si el consenso se rompe en el modelo de contrato-mensaje. Si dos nodos tienen una opinión diferente sobre cómo debe responder un contrato a un mensaje en particular, esto puede conducir a una diferencia en el contenido de sus bases de datos. Esto a su vez puede afectar la respuesta del contrato a mensajes futuros, incluidos los mensajes que envía a otros contratos. El resultado final es una divergencia creciente entre la vista de diferentes nodos del estado de la base de datos. (El campo "raíz de estado" en los bloques Ethereum garantiza que cualquier diferencia en las respuestas de los contratos conduzca inmediatamente a una bifurcación de blockchain completamente catastrófica, en lugar de arriesgarse a permanecer oculto durante un período de tiempo).

Fuentes de no determinismo

Entonces, el no determinismo en el código blockchain es claramente un problema. Pero si los componentes básicos de la computación, como la aritmética, son deterministas, ¿de qué tenemos que preocuparnos? Bueno, resulta que bastantes cosas:

  • Obviamente, los generadores de números aleatorios, ya que, por definición, están diseñados para producir un resultado diferente cada vez.
  • Verificando la hora actual, ya que los nodos no procesarán las transacciones exactamente al mismo tiempo y, en cualquier caso, sus relojes pueden no estar sincronizados. (Todavía es posible implementar reglas dependientes del tiempo haciendo referencia a las marcas de tiempo dentro de la propia cadena de bloques).
  • Consultar recursos externos como Internet, archivos de disco u otros programas que se ejecutan en una computadora. No se puede garantizar que estos recursos siempre den la misma respuesta y pueden no estar disponibles.
  • Ejecutar múltiples piezas de código en "hilos" paralelos, ya que esto conduce a una "condición de carrera" donde el orden en que finalizan estos procesos no puede predecirse.
  • Realizar cualquier cálculo de coma flotante que pueda dar incluso respuestas minuciosamente diferentes en diferentes arquitecturas de procesador de computadora.

Nuestras cuatro plataformas blockchain emplean varios enfoques diferentes para evitar estos escollos.

Ejecución determinista

Comencemos con Ethereum, ya que su enfoque es el más "puro". Los contratos de Ethereum se expresan en un formato de propósito especial llamado "código de bytes de Ethereum", que es ejecutado por la máquina virtual de Ethereum ("EVM"). Los programadores no escriben bytecode directamente, sino que lo generan o "compilan" a partir de un lenguaje de programación similar a JavaScript llamado Solidity. (Otros lenguajes solían estar disponibles pero desde entonces han quedado en desuso). El determinismo está garantizado por el hecho de que el bytecode Solidity y Ethereum no puede codificar ninguna operación no determinista; es así de simple.

Los filtros MultiChain y los contratos Corda eligen un enfoque diferente, adaptando los lenguajes de programación existentes y los entornos de tiempo de ejecución. MultiChain usa JavaScript ejecutándose en Google V8 motor, que también forma el núcleo del navegador Chrome y la plataforma Node.js, pero con las fuentes de no determinismo desactivadas. Del mismo modo, Corda usa Java o Kotlin, los cuales se compilan en "Java bytecode" que se ejecuta dentro de una máquina virtual Java ("JVM"). Por ahora, Corda utiliza la JVM no determinista estándar de Oracle, pero se está trabajando para integrar un versión determinista. Mientras tanto, los desarrolladores de contratos de Corda deben tener cuidado de no permitir el no determinismo en su código.

¿Cómo se compara el purismo de Ethereum con el enfoque evolutivo adoptado por MultiChain y Corda? La principal ventaja de Ethereum es la minimización de riesgos: es menos probable que una máquina virtual creada para un propósito contenga una fuente inadvertida de no determinismo. Si bien dicha supervisión podría solucionarse mediante una actualización de software, sería perjudicial para cualquier cadena que tuviera la mala suerte de encontrarla. Sin embargo, el problema de Ethereum es que Solidity y el EVM constituyen un ecosistema pequeño y naciente en el contexto más amplio de lenguajes de programación y entornos de tiempo de ejecución. En comparación, JavaScript y Java son los dos idiomas principales en Github, se ejecutan en miles de millones de dispositivos digitales y tienen tiempos de ejecución que se han optimizado durante décadas. Presumiblemente, esta es la razón por la cual la cadena de bloques pública Ethereum está considerando una transición a eWASM, una bifurcación determinista del estándar emergente de WebAssembly.

Determinismo por endoso

Cuando se trata de determinismo, Hyperledger Fabric adopta un enfoque completamente diferente. En Fabric, cuando un nodo "cliente" quiere enviar un mensaje a algún chaincode, primero envía ese mensaje a algunos nodos "endosantes". Cada uno de estos nodos ejecuta el chaincode de forma independiente, formando una opinión sobre el mensaje efecto en la base de datos de ese chaincode. Estas opiniones se envían al cliente junto con una firma digital que constituye un "respaldo" formal. Si el cliente recibe suficientes endosos del resultado previsto, crea una transacción que contiene esos endosos y lo transmite para su inclusión en la cadena.

Para garantizar el determinismo, cada pieza de chaincode tiene una "política de respaldo" que define exactamente qué nivel de aprobación se requiere para que sus transacciones sean válidas. Por ejemplo, una política de chaincode podría indicar que se requieren endosos de al menos la mitad de los nodos de blockchain. Otro podría requerir un respaldo de cualquiera de las tres partes de confianza. De cualquier manera, cada nodo puede verificar independientemente si se recibieron los endosos necesarios.

Para aclarar la diferencia, el determinismo en la mayoría de las plataformas blockchain se basa en la pregunta: "¿Cuál es el resultado de ejecutar este código en estos datos?" - y debemos estar absolutamente seguros de que cada nodo responderá esta pregunta de manera idéntica. Por el contrario, el determinismo en Fabric se basa en una pregunta diferente: "¿Están de acuerdo suficientes endosantes sobre el resultado de ejecutar este código en estos datos?" Responder eso es una cuestión bastante simple de contar, y no hay lugar para que el no determinismo se arrastre.

El determinismo de Fabric por endoso tiene una serie de consecuencias interesantes. Primero, chaincode se puede escribir en muchos lenguajes de programación diferentes, ya que no es necesario adaptarlos para el determinismo (actualmente se admiten Go, Java y JavaScript). En segundo lugar, el chaincode puede ocultarse a algunos de los participantes de una cadena de bloques, ya que solo debe ser ejecutado por clientes y patrocinadores (la base de datos en sí es visible a nivel mundial). Finalmente y más notablemente, Fabric Chaincode puede hacer cosas que están prohibidas en otros entornos de blockchain, como verificar el clima utilizando una API web en línea. En el peor de los casos, donde cada endosante obtiene una respuesta diferente de esta API, el cliente no obtendrá suficientes endosos para ningún resultado en particular, y no se realizará ninguna transacción. (Cabe señalar que los miembros del equipo de Fabric todavía recomiendan usando lógica determinista dentro de chaincode, para evitar sorpresas).

¿Qué precio paga Fabric por esta flexibilidad? Si el propósito de una cadena de bloques es eliminar intermediarios de una aplicación compartida basada en bases de datos, entonces la dependencia de Fabric en los endosantes se aleja un paso de ese objetivo. Para los participantes en la cadena, ya no es suficiente seguir las reglas del chaincode; también necesitan ciertos otros nodos para aceptar que lo han hecho. Peor aún, un subconjunto malicioso de endosantes podría aprobar cambios en la base de datos que no siguen en absoluto a chaincode. Esto le da a los endosantes mucho más poder que los validadores en blockchains regulares, que pueden censurar las transacciones pero no pueden violar las reglas de blockchain. Los desarrolladores de aplicaciones Blockchain deben decidir si esta compensación tiene sentido en su caso particular.

Determinismo Telas MultiChain Ethereum Cuerda
Modelo Avales Tiempo de ejecución adaptado VM especialmente diseñada Tiempo de ejecución adaptado
Idiomas Ir + Java + JavaScript JavaScript Solidez Java + Kotlin
Código de visibilidad Contrapartes +
patrocinadores
Servicios Servicios Contrapartes +
dependientes
forzada No No por el momento)

Prevención de conflictos

Hasta ahora, hemos discutido cómo las diferentes plataformas de blockchain expresan las reglas de transacción en el código, y cómo determinan de manera determinista que cada nodo aplique esas reglas de manera idéntica. Ahora es el momento de hablar sobre un tercer aspecto de nuestro enfrentamiento: ¿Cómo maneja cada plataforma la posibilidad de que dos transacciones, que son válidas en sí mismas, entren en conflicto entre sí? En el ejemplo más simple, imagine que Alice tiene $ 10 en un libro de contabilidad financiera y transmite dos transacciones: una que envía $ 8 a Bob y la otra que envía $ 7 a Charlie. Claramente, solo una de estas transacciones puede tener éxito.

Dos modelos

Podemos comenzar agrupando el enfoque de MultiChain y Corda sobre este problema. Como se describió anteriormente, ambos utilizan un modelo de entrada-salida para representar las transacciones y sus reglas, en el que cada entrada de transacción gasta una salida de transacción anterior. Esto lleva a un principio simple para prevenir conflictos: cada salida solo puede gastarse una vez. Los filtros MultiChain y los contratos Corda pueden confiar en sus respectivas plataformas para hacer cumplir esta restricción absolutamente. Dado que los $ 10 de Alice están representados por una salida de transacción anterior, esta regla de gasto único automáticamente detiene su envío a Bob y Charlie.

A pesar de esta similitud, es importante señalar una diferencia clave en cómo MultiChain y Corda previenen conflictos. En MultiChain, cada nodo ve cada transacción y, por lo tanto, puede verificar de forma independiente que cada salida solo se gasta una vez. Cualquier transacción que realice una doble inversión contra una transacción previamente confirmada será rechazada de forma instantánea y automática. Por el contrario, en Corda no existe una cadena de bloques global, por lo que se requieren "notarios" para evitar estos gastos dobles. Cada estado de salida de Corda se asigna a un notario, que debe firmar cualquier transacción que gaste esa salida, confirmando que no se ha gastado antes. Los participantes de una cadena de bloques deben confiar en los notarios para que sigan esta regla honestamente, y los notarios maliciosos pueden causar estragos a voluntad. Al igual que con los avales en Fabric, esto "gasto único como servicioEl diseño tiene ventajas en términos de confidencialidad pero reintroduce a los intermediarios, yendo en contra del grano de la cadena de bloques. (Es importante aclarar que los notarios de Corda pueden ser administrados por grupos de participantes utilizando un algoritmo de consenso, por lo que la integridad del libro mayor aún puede protegerse contra los malos actores individuales).

Pasemos a Ethereum. Para recordar, Ethereum usa contratos y mensajes en lugar de entradas y salidas. Como resultado, los conflictos de transacciones, como los dos pagos de Alice, no son visibles de inmediato para el motor de blockchain. En cambio, son detectados y bloqueados por el contrato que procesa las transacciones, una vez confirmado su pedido en la cadena. Al procesar cada uno de los pagos de Alice, el contrato verifica si su saldo es suficiente. Si la transacción que paga $ 8 a Bob es lo primero, se procesará como de costumbre, dejando a Alice con $ 2 en su cuenta. Como resultado, cuando el contrato procesa la segunda transacción pagando $ 7 a Charlie, ve que Alice carece de los fondos necesarios y la transacción se cancela.

Salidas vs contratos

Hasta ahora hemos visto dos técnicas diferentes para evitar transacciones en conflicto: resultados de un solo gasto en MultiChain y Corda, y verificación basada en contratos en Ethereum. Entonces, ¿cuál es mejor?

Para ayudar a responder esta pregunta, consideremos un ejemplo de cuenta "1-de-2 multifirma" que tiene $ 100 en nombre de Gavin y Helen, y permite a cualquiera de ellos gastar ese dinero de forma independiente. Gavin le indica a su solicitud que pague $ 80 a Donna, y unos segundos después, Helen quiere enviar $ 40 a Edward. Como no hay fondos suficientes para ambos pagos, estas transacciones inevitablemente entrarían en conflicto. En el caso de que ambas transacciones se transmitan, el resultado será determinado por quien lo haga primero en la cadena. Tenga en cuenta que a diferencia del ejemplo de Alice, este conflicto es accidentalmente, dado que nadie está tratando de romper las reglas de la aplicación, simplemente tuvieron un momento desafortunado.

Al considerar la probabilidad de que ocurra este conflicto, la pregunta clave es la siguiente: después de que Gavin envíe su transacción, ¿cuánto tiempo le tomará al nodo de Helen saber que su pago podría fallar? Cuanto más corto sea este período, es más probable que se le impida a Helen que intente ese pago, lo que la salvará a ella y su solicitud de una sorpresa posterior.

Con el modelo de entrada-salida, cualquier conflicto entre transacciones es directamente visible para la plataforma blockchain, ya que las dos transacciones intentarán explícitamente gastar la misma salida anterior. En MultiChain, esto sucede tan pronto como la transacción de Gavin se ha propagado al nodo de Helen, generalmente en un segundo o menos. En Corda, el notario de la producción rechazará la solicitud de firmar la transacción de Helen, ya que ya ha firmado la de Gavin, por lo que Helen sabrá al instante que su pago fallará. (Aunque si el notario Corda se distribuye, puede que tenga que esperar unos segundos para recibir una respuesta). De cualquier manera, no hay necesidad de esperar a que se confirme y se ordene una transacción en blockchain.

¿Qué pasa con el modelo de Ethereum? En este caso, no hay forma inmediata para que la plataforma blockchain sepa que ocurrirá un conflicto. Si bien el nodo de Helen puede ver la transacción de Gavin en la red, no puede saber cómo esto afectará la transacción de Helen, ya que desde su perspectiva, estos son simplemente dos mensajes que se envían al mismo contrato. Tal vez diez segundos después, una vez que se confirme el orden final de las transacciones en conflicto en la cadena de bloques, el nodo de Helen volverá a calcular el resultado real en lugar del esperado, y su aplicación actualizará su visualización en consecuencia. Mientras tanto, tanto Gavin como Helen se quedarán en la oscuridad.

Pero no deberíamos concluir de esto que el modelo de entrada-salida siempre funciona mejor. Considere una variación en nuestro escenario de ejemplo, donde Gavin y Helen solicitan pagos menores de $ 40 del saldo original de $ 100, exactamente al mismo tiempo. En el modelo de entrada-salida, estas transacciones entrarían en conflicto, ya que ambas gastan la misma fila de la base de datos que contiene esos $ 100, y solo uno de los pagos tendría éxito. Pero en Ethereum, ambas transacciones se procesarían con éxito, independientemente de su orden final, ya que la cuenta contiene fondos suficientes para ambas. En este caso, Ethereum cumple más fielmente las intenciones de Gavin y Helen.

Conjuntos de lectura y escritura

Finalmente, hablemos de Fabric, cuyo enfoque basado en el respaldo es un híbrido de estas dos técnicas. Como se explicó anteriormente, cuando un nodo "cliente" de Fabric desea enviar un mensaje a un contrato, primero le pide a algunos nodos endosantes que ejecuten ese mensaje en su nombre. Los nodos de respaldo lo hacen de manera similar a Ethereum, ejecutando el contrato en su base de datos local, pero este proceso se observa en lugar de aplicarse de inmediato. Cada endosante registra el conjunto de filas que se leerían y escribirían, señalando también la versión exacta de esas filas en ese momento. Este "conjunto de lectura y escritura" de filas versionadas se menciona explícitamente en el endoso y se incluye en la transacción que el cliente transmite.

Los conflictos entre las transacciones de Fabric se resuelven una vez que se finaliza su pedido en la cadena. Cada nodo procesa cada transacción de forma independiente, verifica las políticas de aprobación y aplica los cambios de base de datos especificados. Sin embargo, si una transacción lee o escribe una versión de fila de base de datos que ya ha sido modificada por una transacción anterior, entonces esa segunda transacción se ignora. Para volver a los pagos conflictivos de Alice a Bob y Charlie, ambas transacciones leerán y modificarán la misma versión de la fila, que contiene los $ 10 con los que Alice comenzó. Por lo tanto, la segunda transacción se cancelará de forma segura y automática.

El enfoque de Fabric para la resolución de conflictos funciona bien, pero en términos de rendimiento y flexibilidad combina lo peor de los dos modelos anteriores. Debido a que los endosos convierten las transacciones en conjuntos específicos de lectura y escritura, los pagos simultáneos pero compatibles de $ 40 de Gavin y Helen conducirían a un conflicto que Ethereum evita. Sin embargo, Fabric no obtiene la ventaja de velocidad del modelo de entrada-salida, ya que los endosantes ejecutan contratos contra la versión más reciente de la base de datos confirmada por blockchain, ignorando las transacciones no confirmadas. Entonces, si Helen inicia su pago unos segundos después de Gavin, pero antes de que se confirme el de Gavin en la cadena de bloques, Fabric creará transacciones conflictivas que evita un modelo de entrada-salida puro.

Prevención de conflictos Telas MultiChain Ethereum Cuerda
Modelo Conjuntos de lectura y escritura Gasto individual Cheques de contrato Gasto individual
Verificación Independiente Independiente Independiente Notarios de confianza
Velocidad ~ 10s (confirmación) ~ 1s (propagación) ~ 10s (confirmación) 0 ~ 5s (notario)

Una elección compleja

En este artículo, revisamos muchas de las diferentes formas en que Corda, Ethereum, Fabric y MultiChain abordan los desafíos clave de los "contratos inteligentes", o el código de aplicación que está incrustado en una cadena de bloques. Y cada plataforma tiene diferentes respuestas a nuestras tres preguntas principales: ¿Cómo se representan las reglas de transacción? ¿Cómo se ejecuta el código de manera determinista? ¿Y cómo prevenimos los conflictos?

Entonces, ¿quién es el ganador de nuestro enfrentamiento de contrato inteligente? Ya debería ser obvio que no hay una respuesta simple. Cada plataforma representa un complejo equilibrio multidireccional entre flexibilidad, simplicidad, rendimiento, desintermediación, seguridad y confidencialidad. Por lo tanto, la elección de la plataforma para una aplicación en particular debe comenzar con una comprensión detallada del modelo de confianza de esa aplicación, los tipos de transacciones que involucra y sus posibles patrones de conflicto. Si encuentra que alguien está impulsando una solución de contrato inteligente específica antes de que sepan las respuestas a estas preguntas, sugiero cortés pero firmemente insistir en que adopten un enfoque "más inteligente".

Por favor publique cualquier comentario en Linkedin.

Sello de tiempo:

Mas de Multicain