Diseño de la arquitectura para su aplicación Ethereum

A medida que comienza con el desarrollo de Ethereum, y después de pasar por algunas de las muchas publicaciones excelentes de tutoriales, se enfrenta al desafío de crear su primera aplicación basada en Ethereum.

Esto plantea una serie de nuevos desafíos en torno al diseño de la arquitectura y el diseño de su aplicación: las aplicaciones cliente-servidor tradicionales ahora tienen un tercer componente nuevo en la mezcla, la cadena de bloques .

En este artículo, cubriré algunos de los escenarios más tradicionales para las aplicaciones de Ethereum, que surgen de las diferentes interacciones entre estos tres componentes. Hablaré de las aplicaciones sin servidor, los complementos del navegador, los nodos privados, la firma sin conexión y otros problemas que influyen en el diseño del diseño de sus soluciones.

Cliente-blockchain en aplicaciones sin servidor

El sabor canónico de una aplicación Ethereum es sin servidor, donde todo el flujo de su aplicación ocurre entre el cliente y la cadena de bloques.

El primer paso aquí es distribuir el código de cliente a sus usuarios. La forma más sencilla es configurar una página estática que contenga una aplicación web habilitada para web3. Dicha página se puede alojar en cualquier lugar: AWS S3, Google Cloud, páginas de Github, otros proveedores de la nube o su propio servidor. Además, si puede contar con que sus clientes admitirán el protocolo bzz o ipfs , incluso puede distribuirlo a través de Swarm o IPFS para una descentralización total.

Consultando la cadena de bloques

El siguiente paso es que la aplicación pueda leer información de la cadena de bloques, que, como ya sabe, requiere una conexión a un nodo Ethereum activo. Esto lo establecerá su proveedor web3, que es la pieza que maneja la conexión web3 real a un nodo.

Ahora, es posible que algunos de sus usuarios ya tengan una conexión establecida con un nodo, por ejemplo, a través del cliente oficial Mist o mediante un complemento de navegador como el popular Metamask , que actúa como un cliente ligero para blockchain. Sus preguntas frecuentes incluso proporcionan un fragmento de código sobre cómo detectar si está disponible en un cliente y utilizarlo como proveedor para web3.

¿Qué hacer entonces para aquellos usuarios que no tienen Mist o Metamask? Si solo los necesita para consultar la cadena de bloques sin enviar ninguna transacción, puede establecer una conexión a un nodo público de Ethereum . Este debe ser un nodo geth o de paridad abierto al público, pero sin exponer la API personal para administrar cuentas, y sin cuentas desbloqueadas. Dicho nodo solo actuará como una puerta de enlace para consultar funciones de contrato constante. Y si no desea alojarlo usted mismo, la gran gente de Infura ofrece nodos públicos sin costo.

De esta manera, los usuarios con una infraestructura Ethereum en ejecución pueden usar sus conexiones a sus propios nodos de confianza, y los usuarios con menos conocimientos tecnológicos pueden usar los nodos públicos. Esto implica que los últimos usuarios eligen confiar en la información proporcionada por el nodo controlado por terceros, en aras de la facilidad de uso.

Envío de transacciones

Consultar la cadena de bloques es fácil, pero ¿qué sucede si desea que sus usuarios envíen transacciones y, de hecho, realicen acciones de cambio de estado en contratos inteligentes?

Para aquellos de sus usuarios que tienen Mist o Metamask instalado, el problema se resuelve instantáneamente, ya que ambos brindan una forma de administrar las cuentas de usuario y solicitar al usuario que apruebe una transacción en el solicitud de la aplicación. Mist proporcionará una puerta de entrada al nodo local del usuario y sus cuentas para firmar transacciones, mientras que Metamask firmará transacciones del lado del cliente y las retransmitirá a los nodos públicos de Metamask.

En cuanto al resto de sus usuarios, si no les pide que instalen Metamask o usen Mist para usar su aplicación, deberá indicarles que envíen manualmente las transacciones para interactuar. con su aplicación, desde cualquier billetera con la que trabajen.

La mayoría de las aplicaciones implementan esto pidiendo al usuario que envíe una cierta cantidad de ETH a una dirección, que opcionalmente incluye un QR o un botón de copia al portapapeles.

Su aplicación del lado del cliente puede entonces monitorear los eventos del contrato para actualizar la interfaz de usuario a medida que se ejecuta la transacción enviada fuera de banda. Dado que ver eventos es simplemente una forma de consultar la cadena de bloques, se puede hacer fácilmente a través de un nodo público.

Ahora, para ejecutar funciones de contrato, es posible que deba solicitar al usuario que envíe ETH junto con datos adicionales para ejecutar una función específica. Puede utilizar el método request de una función de contrato para obtener fácilmente los datos necesarios para ejecutar un método y presentarlos al usuario junto con la dirección de destino.

Personalmente, no soy un gran admirador de este patrón, ya que requiere una interacción bastante compleja por parte del usuario . No todos los usuarios saben cómo funcionan los datos adicionales en Ethereum, y mucho menos cómo enviarlos en una transacción.

Si necesita implementarlo, asegúrese de que la función de respaldo de su contrato rechace todos los pagos o tenga un comportamiento predeterminado razonable, de modo que si el usuario se olvida de incluir los datos adicionales al enviar manualmente la transacción, no pierde los fondos enviado.

Tenga en cuenta que, en muchos escenarios, una función de reserva diseñada inteligentemente en realidad siempre puede ejecutar el comportamiento esperado para el usuario que envía una transacción. De esta manera, sus contratos inteligentes simplemente reaccionan a los usuarios que envían fondos y ejecutan diferentes funciones según el estado actual, sin requerir que el usuario establezca ningún dato adicional.

Otro truco es agregar contratos de proxy, donde cada uno de ellos ejecuta una función particular en su contrato principal al recibir Ether. Como ejemplo simple, digamos que está implementando una aplicación de votación binaria: tiene su contrato principal con una función de voto-sí y una función de voto-no. En lugar de pedirle al usuario que incluya la marca de sí o no en su transacción, puede implementar dos contratos adicionales, sin lógica, excepto para llamar voto-sí o voto-no en el contrato principal en nombre del remitente del mensaje al recibir cualquier transacción. No hace falta decir que este enfoque solo funciona en aplicaciones bastante simples, pero a menudo puede ayudar a reducir la complejidad para los usuarios que no tienen software compatible con Ethereum en sus navegadores.

Implementación de su propia billetera

Otra opción para que sus usuarios realicen interacciones complejas con sus contratos inteligentes es agrupar la administración de billetera en su aplicación. Como primer paso para un usuario, la aplicación puede crear una nueva cuenta para él , que se utilizará para enviar cualquier transacción directamente desde su código.

El usuario deberá entonces sembrar esta cuenta con algo de Ether, ya sea desde una cuenta diferente o directamente desde un servicio de intercambio; considere incluir una integración de Shapeshift aquí para facilitar su uso. Una vez que la cuenta tiene el saldo requerido para pagar las tarifas de transacción, el código del lado del cliente puede ejecutar cualquier operación necesaria en nombre del usuario con un simple clic.

Detrás de escena, su aplicación utilizará la clave privada de la cuenta generada para firmar cualquier transacción en el lado del cliente y luego las retransmitirá a un nodo público para su ejecución.

Este patrón implica una codificación pesada, ya que necesita agregar las características de generar y cifrar, así como importar, una cuenta ethereum (es posible que desee echar un vistazo a la biblioteca ethereum-wallet para implementaciones de estas tareas). Además, todas las transacciones deben diseñarse y firmarse manualmente y luego enviarse como transacciones sin procesar a un nodo. También requiere una mayor participación del usuario, que tiene la tarea de configurar una nueva cuenta y la responsabilidad de proteger el archivo de la cuenta.

Sin embargo, una vez configurado, su usuario puede realizar transacciones de Ethereum directamente desde su aplicación sin ningún tipo de fricción y sin necesidad de instalar ningún software.

En general, el enfoque que utilice dependerá en gran medida del tipo de usuarios a los que se dirija, así como del tipo de interacción que espera que tengan con su aplicación, ya sea de uso continuo, poco frecuente o accesos únicos.

Servidor a blockchain

Ahora, agreguemos un servidor a la mezcla y dejemos al cliente a un lado para esta sección. Como tal, lo siguiente puede aplicarse no solo a los servidores de aplicaciones, sino también a aplicaciones independientes, scripts o procesos por lotes.

Configuración de un nodo local

La primera solución es la básica: configure un nodo Ethereum local y use su interfaz JSON RPC desde su aplicación para realizar todas sus operaciones de blockchain.

Es posible que también desee mantener una cuenta desbloqueada para ejecutar transacciones desde su aplicación (la marca desbloquear para Geth y Parity puede resultar útil aquí). Solo asegúrese de que la interfaz JSON RPC del nodo no sea accesible desde cualquier lugar que no sea su aplicación ; de lo contrario, cualquiera puede acceder a su nodo y robar sus fondos. Como precaución adicional, mantenga los fondos en la cuenta desbloqueada al mínimo y genere los fondos de una fuente diferente según sea necesario.

Firma sin conexión y nodos públicos

Otra solución, similar a la que se exploró en la sección anterior, es hacer que su aplicación firme transacciones sin conexión y las transmita a un nodo público. Este artículo explora cómo configurar un motor de proveedor web3 en su configuración de Truffle para firmar de forma transparente transacciones fuera de línea y enviarlas a un nodo Infura.

Si sigue esta ruta, tenga en cuenta que está confiando ciegamente en el nodo público al que se está conectando: aunque no puede modificar las transacciones que le envía, puede optar por no retransmitir a la red, o para proporcionar respuestas falsas a sus consultas. Esto podría mitigarse conectándose a varios nodos simultáneamente y enviando las mismas transacciones o consultas a todos ellos; pero esto hace que su base de código sea mucho más compleja.

Uniéndolo todo

Después de pasar por diferentes formas de configurar consultas y transacciones cliente-blockchain y servidor-blockchain, es hora de discutir cómo organizar todo junto.

Coordinando cliente y servidor

Tener tanto al cliente como al servidor interactuando simultáneamente con la cadena de bloques implica que es posible que deba coordinarlos a ambos. Por ejemplo, es posible que desee que el servidor reaccione a una acción realizada en cadena por un cliente, o visualizar en un cliente ciertos cambios de estado en un contrato.

La forma canónica de observar cambios en un contrato, tanto desde el cliente como desde el servidor, es escuchar los eventos del contrato . Diseñe sus eventos con cuidado, para asegurarse de que todas las acciones relevantes tengan un evento asociado, y use argumentos indexados para que los observadores puedan filtrar solo los eventos relevantes para ellos. Por lo general, un cliente solo escuchará los eventos que lo afecten directamente, mientras que los servidores pueden monitorear todos los contratos relacionados con la aplicación.

También puede monitorear transacciones específicas directamente si se emiten directamente desde el código de su aplicación, para verificar que se realicen correctamente.

Los clientes también pueden publicar en el servidor la identificación de una transacción que emitieron como prueba de una acción ejecutada en cadena, en lugar de que el servidor escuche eventos. Sin embargo, tenga en cuenta que un actor malintencionado puede estar monitoreando transacciones en cadena y podría enviar al servidor una identificación de transacción de un cliente diferente, fingiendo que le pertenece. Asegúrese de utilizar los mensajes de cliente a servidor solo como notificaciones y no como fuentes de la verdad.

Independientemente de depender de la supervisión de transacciones o eventos, asegúrese de reaccionar ante ellos solo después de un número razonable de confirmaciones . Incluso si tiene una transacción extraída, aún podría estar sujeta a una reorganización en cadena y, finalmente, ejecutarse en un contexto diferente, lo que podría dejar de ser válida. Espere alrededor de una docena de bloques (más en redes de prueba) antes de actuar sobre un evento en cadena, aunque considere informar a su usuario final que la transacción fue exitosa pero no está confirmada, para no mantenerlos en la oscuridad.

Responsabilidades del servidor

Ahora, una pregunta fundamental que debe responder es por qué necesita un servidor . En las aplicaciones cliente-servidor tradicionales, el servidor actúa como un almacenamiento permanente, refuerza la lógica empresarial y coordina a los clientes; todas las tareas que ahora se pueden realizar en cadena.

No obstante, todavía existen muchos usos para un servidor que respalda su aplicación. En primer lugar, el código en cadena no puede funcionar directamente con servicios fuera de cadena . Esto significa que si desea integrarse con servicios de terceros, inyectar datos externos como tarifas USD / ETH o realizar acciones básicas como enviar un correo electrónico, necesita un servidor que se encargue de esto.

El servidor también puede actuar como caché o motor de indexación para sus contratos inteligentes . Si bien la principal fuente de la verdad es la cadena de bloques, sus clientes pueden confiar en el servidor para las capacidades de búsqueda y validar los datos devueltos en la cadena.

El almacenamiento de datos grandes es prohibitivamente caro hoy en Ethereum, debido a los costos de gas incurridos en el uso del almacenamiento por contrato. Como tal, su aplicación también puede depender de un servidor para almacenar grandes cantidades de datos , mientras que solo se mantiene un hash en la cadena para su verificación. Lo mismo ocurre con los cálculos complejos, que pueden superar el límite de gas del bloque Ethereum y, por lo tanto, deben ejecutarse en una infraestructura separada.

Vale la pena mencionar que cada vez aparecen más proyectos en torno a EVM que brindan una integración perfecta con estos servicios. Algunos ejemplos son Filecoin o Storj para almacenamiento, Truebit para computación u Oraclize para oráculos. Eventualmente, los servidores pueden volverse más y más delgados hasta que desaparezcan en una miríada de servicios e integraciones de cadena lateral. Tal vez, dentro de unos años, esta publicación sea obsoleta y nuestras aplicaciones blockchain se ejecuten de manera absolutamente descentralizada.

Sea parte de la comunidad