Lightning Rust
Oradores: Matt Corallo
Fecha: February 7, 2019
Transcripción De: Michael Folkson
Traducción Por: Blue Moon
Tags: Lightning
Categoría: Conferencia
Media: https://www.youtube.com/watch?v=w_To_bnXjvk
Lightning flexible en Rust
Diapositivas: https://docs.google.com/presentation/d/154bMWdcMCFUco4ZXQ3lWfF51U5dad8pQ23rKVkncnns/edit#slide=id.p
https://twitter.com/kanzure/status/1144256392490029057
Introducción
Gracias por recibirme. Quiero hablar un poco sobre un proyecto en el que he estado trabajando durante un año llamado “Rust-lightning”. Lo empecé en diciembre, así que hace un año y unos meses. Esta es mi primera presentación en él, así que estoy emocionado de finalmente llegar a hablar de ello un poco.
Objetivos
Es otra implementación de Lightning porque de alguna manera necesitábamos otra supongo o realmente no. Pero hace un año y pico decidí que quería aprender Rust. Todo el mundo está súper entusiasmado con Rust. ¿Qué es esta cosa? Tal vez hay algo aquí para ello. También quería aprender un poco sobre Lightning. No teníamos a nadie en Chaincode que hubiera trabajado en alguna cosa de Lightning. Yo quería entrar en la carne de ella porque estábamos sólo una tienda de Bitcoin Core o laboratorio de investigación por lo que es agradable tener personas que conocen todas las diferentes piezas. Me imaginé que hay esta cosa de la especificación aquí, pero la mayoría de las implementaciones se han hecho por el trabajo con los demás y sería bueno tener algo que se hace completamente en una sala limpia sólo de la especificación, sólo para ver lo bueno que la especificación es, para mejorarla, para proporcionar retroalimentación y ver qué tipo de conceptos erróneos que pueden venir acerca de cómo se supone que Lightning para trabajar con sólo leer la especificación sin leer ninguna de las otras implementaciones. Resulta que había un número de ellos, la especificación es buena, pero podría utilizar un poco … De todos modos me puse en marcha y empecé a trabajar en esto y escribirlo. Fue divertido y aprendí mucho sobre Rust y mucho sobre Lightning. Me di cuenta de que hay un pequeño nicho en el ecosistema de nodo de relámpago que realmente no se llena en absoluto. Eso es para no ser un nodo de venta al por mayor y proporcionar a la gente la flexibilidad para integrar Lightning en la forma que quieren. Hoy en día usted puede ir a tomar c-lightning y se puede ejecutar y tiene una gran interfaz y funciona. O puedes coger lnd y puedes ejecutarlo y comunicarte a través de gRPC. Puedes tomar Eclair e incluso eso tiene un montón de cómo interactúa con otros compañeros construidos e incorporados y cómo maneja las claves y todas esas cosas. No hay realmente una buena implementación de Lightning que traiga su propia creación de claves y que descubra cómo quiere que funcione la UX, que descubra cómo quiere que funcione el almacenamiento en disco, cómo quiere exactamente que encajen todas las piezas. Ese es el nicho en el que me he deslizado tratando de llenar con este proyecto. Los principales casos de uso iniciales soportados son, en primer lugar, los monederos existentes. Tenemos este gran ecosistema de monederos de Bitcoin, la mayoría de ellos no soportan Lightning porque ¿cómo habrían soportado Lightning hace un año? ¿Cómo van a integrar Lightning sin empezar completamente desde cero, consiguiendo todos los detalles del protocolo correcto y haciendo una tonelada de trabajo para asegurarse de que manejan todos los casos posibles en Lightning correctamente. Así que esperemos que Rust-Lightning sea una cosa fácil que se pueda sacar de la estantería, que se pueda integrar estrechamente con toda la gestión existente de UTXO y el estado de la cadena y todo. Se ocupa del resto para usted. Se ocupa de la gestión de canales y de la gestión de pares y de todas esas cosas buenas. El otro caso de uso que quiero apoyar un poco mejor es la flexibilidad en torno a la forma de hacer, si se trata de una cartera de hardware o si se trata de estos nodos parcialmente fuera de línea y voy a entrar en un poco más de lo que quiero decir con eso en un minuto, pero dejar que la gente tenga más alta garantía o por lo menos diferentes modelos de seguridad en torno a la forma en que ejecutan su nodo Lightning en lugar de sólo tengo un servidor en línea y pongo los fondos en él y confío en que no va a ser hackeado. Ahí es donde ha ido y ha hecho muchos progresos. En su mayor parte está ahí. Hay algunas cosas que quiero cambiar en términos de conseguir los últimos bits de manejo onchain implementado y luego quiero esperar a que algunas de las cosas de la especificación 1.1 en Lightning antes de enviarlo porque eso simplifica una gran cantidad de las interfaces para los clientes, especialmente en torno a la gestión de las tasas.
Estructura de la biblioteca
Así que, a alto nivel, ¿qué aspecto tiene rust-lightning? No hay tiempo de ejecución. Lo bueno de Rust es que no hay tiempo de ejecución, no hay hilos de fondo, no hay recolección de basura, nada de eso. No se necesita una JVM. No es como Go donde tienes estos hilos que necesitan ser iniciados y ejecutar la recolección de basura y todo ese tipo de cosas. Rust-lightning es totalmente impulsado por eventos. Así que lo llamas y no hace nada a menos que lo llames. No tiene un hilo de fondo por lo que tiene que hacerlo. Esto significa que es incrustado en todas partes. Si puedes compilar a LLVM y puedes compilar código C a tu objetivo puedes ejecutar rust-lightning con suerte. Hay algunas piezas más para trabajar en eso, pero se puede ejecutar en cualquier lugar, incluyendo carteras de hardware, incluyendo WASM ese tipo de cosas. Está diseñado para ser bastante modular. Especialmente las diferentes piezas que usted podría querer haber separado o reemplazar por su cuenta. Eso significa que el enrutamiento, si quieres hacer tu propia gestión de enrutamiento, quieres hacer tu propio algoritmo de enrutamiento, quieres hacer tu propia gestión de la tabla de enrutamiento. Está completamente aislado. Hay una interfaz sencilla para ello. Hay una predeterminada que puedes usar o puedes construir la tuya propia, sin problema. La gestión de los canales está separada de la monitorización real de los mismos. Las piezas que tienen que vigilar la cadena y manejar las actualizaciones de las transacciones en la cadena están separadas de la gestión real de cuál es el estado de todos tus HTLCs y cuál es el estado de todos tus canales. Esto te permite tomar fácilmente las actualizaciones de los canales, de modo que el gestor de canales te da estas actualizaciones que dicen “Oye, he recibido nueva información que necesitas para asegurarte de vigilar la cadena” y te da ese blob. A continuación, puedes averiguar cómo quieres hacer llegar esa información al dispositivo que debe vigilar la cadena. Tal vez tengas varios dispositivos diferentes que vigilan la cadena, es decir, torres de vigilancia. Tal vez los canales reales se gestionan en un dispositivo de hardware y tienes una torre de vigilancia remota, algo así. Esto te permite tener flexibilidad en cuanto a cómo quieres integrar estas cosas. Así que esto es un soporte pseudo nativo de las torres de vigilancia. La forma exacta que adoptan las torres de vigilancia es extraña porque hay muchas compensaciones diferentes en términos de los datos que necesitas firmar por adelantado y proporcionar a la torre de vigilancia. Cuántos datos necesita almacenar frente a cuánto confías en la torre de vigilancia con respecto a la privacidad. Tal vez podría robar tus fondos frente al almacenamiento de muchos datos. Hay muchas compensaciones y creo que la próxima charla cubrirá esto un poco mejor. Esperemos que la mayor parte de esto desaparezca con eltoo y otros trabajos futuros. Hoy en día es complicado, por lo que no hay una flexibilidad total en los tipos de torres de vigilancia todavía en rust-lightning, pero definitivamente si confías en los servidores que están vigilando la cadena para ti o confías en las torres de vigilancia es muy fácil hacer girar un montón de diferentes servidores haciendo torres de vigilancia. Así que la escritura del disco, todo el tipo de piezas de interacción del sistema se manejan en el lado del cliente. Así que rust-lightning no se imagina cómo escribir cosas en el disco. Simplemente te lo entrega y esto te permite tener flexibilidad y decir algo como “Ok aquí hay una actualización que necesitas para ir a actualizar tus torres de vigilancia” y puedes decir “En realidad no pude ponerme en contacto con la torre de vigilancia, por favor pausa ese canal” así que tiene flexibilidad aquí. Resulta que es súper complicado de hacer bien y voy a hablar de eso un poco más cuando voy a algunas de las cosas divertidas que hemos hecho con las pruebas en rust-lightning. El manejo de la pausa de los canales para las actualizaciones de la torre de vigilancia ha sido realmente muy útil en términos de ser capaz de tener flexibilidad en torno a la forma de controlar sus canales. Mencioné que rust-lightning no hace la sincronización de la cadena por ti porque un usuario clave de rust-lightning potencialmente son las carteras existentes y he hablado con un número de carteras existentes que están entusiasmadas con esta idea. Pero todos ellos ya tienen su propia cadena de sincronización. Todos ellos ya son clientes de SPV o tal vez utilizan servidores de Electrum o lo que sea. Esto está diseñado para ser flexible en rust-lightning. Te da toda la información que necesitas de aquí están las transacciones que necesitas vigilar, aquí están exactamente los scripts y los txids y lo que sea para que puedas usar servidores Electrum, puedes usar Neutrino, puedes usar cosas existentes de filtros de floración. Todo es bastante flexible y puedes elegir exactamente cómo quieres integrarte con la cadena Bitcoin. También BYO, RNG y creación de claves. El objetivo es que rust-lightning no haga syscalls por ti, sólo necesita malloc. No está al 100%, pero se está acercando. Eso significa que tienes que tener tu propio RNG. Pero, por supuesto, si estás haciendo un monedero de hardware o algo así, vas a querer usar las características del hardware de todos modos, así que no voy a tratar de adivinar en qué entorno estás corriendo, tienes que conectarlo tú mismo. Finalmente, el manejo de TCP depende de ti también. Hay una interfaz fácil que he escrito que se ve exactamente como select así que puedes asignar esto a un manejador de socket TCP existente súper simple. O puedes consumir los mensajes manualmente y esto ha sido muy útil para las pruebas porque tenemos una tonelada de arneses de prueba que entregan mensajes fuera de orden y retrasan el procesamiento de los mensajes para simular la latencia de la velocidad de la luz entre los nodos, lo que nos ha permitido ser realmente flexibles en términos de cómo probamos la biblioteca.
Carteras existentes
En términos del caso de uso de tener carteras existentes que quieren usar rust-lightning. Hay algunos elementos clave de cómo rust-lightning encaja en eso. En primer lugar, como he mencionado, es de esperar que puede vivir en cualquier tiempo de ejecución. Estoy tratando de no adivinar nada sobre el sistema que se está ejecutando. El objetivo es que no hace syscalls excepto por lo que tiene que ser capaz de llamar a malloc, sin llamadas libc excepto para malloc. No estamos del todo ahí. Actualmente tenemos algunas llamadas de bloqueo que queremos ser capaces de eliminar, pero nos estamos acercando. Así que malloc, que lo hace un poco más difícil con carteras de hardware, pero está cerca. Es completamente c-callable así que no necesitas saber nada de Rust. Sólo necesitas saber cómo llamar a una función en C y enlazar una librería compartida, lo que todos los lenguajes del mundo deberían poder hacer en este momento. Y por último, WASM. El objetivo es poder ejecutar esto completamente en un navegador web. Ya casi estamos, necesitamos eliminar una dependencia más. Puedes compilar rust-lightning y ejecutar un nodo Lightning completo en tu navegador web. No sé exactamente por qué querrías hacer esto, pero en teoría lo apoyamos. Esto lleva a un cierto entusiasmo en torno a la ejecución de nodos Lightning en las extensiones y esto definitivamente le permitirá sincronizar diferentes nodos. Así que tal vez usted tiene su nodo de Lightning y que acaba de mantener una copia encriptada en un servidor de todos los datos para el nodo de Lightning y cuando estás en tu ordenador se ejecuta en su pequeña extensión de Chrome o en su aplicación React Native y luego cuando usted va en su teléfono se descarga el último estado y se detiene el que está en su computadora y lo ejecuta en su teléfono. Es la misma librería que estás ejecutando en todas partes y puedes compilarla como quieras.
Seguridad del hardware
En el modelo de hacer el hardware o un nodo de Lightning mayor garantía. Un objetivo clave es hacer lo que he estado llamando nodos semi-offline, así que son una especie de offline pero en la práctica tienen actualizaciones constantes. Lo que quiero decir con esto es que tal vez usted tiene un HSM o tal vez usted tiene algún otro dispositivo integrado o tal vez usted tiene un servidor regular, pero en realidad no tiene una dirección IP, no puede conectarse a Internet. Sólo tiene una pequeña línea de comunicación con un ordenador normal o con un servidor madre, quizás a través de una serie o de un USB. Usted alimenta toda la comunicación con sus compañeros a través de esa línea y esto le permite tener un dispositivo donde la única cosa que puede comunicarse con el mundo es a través del protocolo Lightning a los compañeros Lightning. No puede ser hackeado a través de otros medios y tal vez es físicamente seguro también. Así que esto es similar a cómo se podría imaginar un Ledger o un Trezor o una cartera de hardware integrando Lightning. El nodo se ejecuta efectivamente en el dispositivo, pero se comunica con los pares a través de cualquier interfaz que tenga. Así que esta es la razón por la que rust-lightning de nuevo no hace las llamadas de socket TCP reales para usted, sólo le dice “Aquí hay bytes. Por favor, envíalo a este peer” o acepta bytes entrantes de un peer. Es muy fácil envolver un socket TCP pero todavía tienes esta flexibilidad para poder hacer otro trabajo de integración loco. Por supuesto, esto deja de lado la cuestión de cómo supervisar la cadena. Uno de los aspectos clave del modelo de seguridad de Lightning es que tienes que tener algo que siempre esté monitoreando la cadena. Así que no se puede pasar completamente a algo como un Ledger o un Trezor o una cartera de hardware porque no está constantemente en línea y no recibe constantemente actualizaciones de la cadena. Así que si está fuera de línea por un tiempo es problemático. Por supuesto, esto es aún peor porque hay algunos casos en Lightning donde tal vez usted tiene un HTLC pendiente pero su contraparte se desconectó y con el fin de reclamar ese HTLC usted necesita seguir adelante y limpiar la cadena antes de algún tiempo de espera. Eso es aún peor porque no sólo tienes que estar monitorizando la cadena en largos periodos de tiempo sino que puedes tener un tiempo específico en el que necesitas emitir esta actualización si no has sido capaz de ponerte en contacto con tu peer en algún tiempo. En rust-lightning tratamos de evitar esto un poco. En realidad no lo hacemos de forma nativa, pero un enfoque clave que se puede imaginar es que si usted tiene esta cartera de hardware o tiene algún dispositivo puede tener pseudo torres de vigilancia de confianza. Estoy usando el término torre de vigilancia un poco sobrecargado aquí. Es una especie de otra mitad de confianza de su nodo. Puedes enviarle una copia encriptada de los datos que necesita monitorear y puede firmar esos datos, enviártelos de vuelta y decir “Sí, lo he recibido, lo he actualizado”. Y entonces todavía no tienes que confiar necesariamente en el ordenador que está entre el ordenador en línea, sino que tienes que confiar en que ese otro dispositivo está monitorizando activamente la cadena y recibe actualizaciones. Esto es todavía un poco agradable porque se puede imaginar si usted está realmente bajando por el agujero del conejo de la ejecución de algunos locos nodo de Lightning de alta seguridad, tal vez usted tiene varias copias de este tipo de servidor. Usted tiene múltiples cosas viendo la cadena para usted en diferentes regiones geográficas y por lo que necesita para ser capaz de tomar estos datos que necesita para ver, enviarlo a varios servidores, obtener la firma de todos los servidores y luego realmente hacer progresos en el canal. Así que rust-lightning soporta pausar el canal temporalmente hasta que hayas actualizado el material de vigilancia, el monitor de la cadena y luego continuará.
Pruebas de diversión
Así que esos son los dos casos de uso clave que se apoyan en rust-lightning. Lo que quiero hablar un poco brevemente es sobre algunas de las cosas que hemos estado trabajando en términos de pruebas y diferentes enfoques que hemos tomado de los nodos existentes que han sido habilitados un poco por accidente por la estructura de la biblioteca. Así que esto no era algo que tenía como un objetivo mío al entrar, pero resulta que sólo porque esta biblioteca es flexible, no tiene un tiempo de ejecución, no tiene ningún syscalls y por lo que no tiene que hacer un montón de trabajo de configuración, significa que podemos ejecutar realmente grandes pruebas que, literalmente, puede soportar diez nodos en el mismo proceso con sólo hacer cuatro llamadas a la función. No tenemos que ir a crear demonios y limpiar cosas en el disco y mover cosas, nada de eso. Nos ha permitido escribir pruebas realmente rápidas y geniales en todo el lugar. Y también, por supuesto, porque tenemos esta interfaz, como he mencionado, de obtener mensajes y ser capaces de manejar esos mensajes manualmente para enviarlos entre pares, también podemos reordenar esos mensajes, podemos retrasarlos y entregarlos en órdenes específicos muy fácilmente moviendo líneas de código en lugar de tener que sentarse realmente en medio de un socket TCP y hackear nuestro demonio o tener un montón de código de prueba en medio de nuestro código de producción. También hemos jugado mucho con fuzzing, creo que he jugado mucho con fuzzing en rust-lightning. Obviamente tenemos fuzzers para todos nuestros deserializadores de mensajes y cosas así. Para aquellos que no están familiarizados, fuzzing ha sido increíblemente útil en todo el mundo del software, pero sobre todo para encontrar vulnerabilidades en cosas como descompresores de imágenes, decodificadores de imágenes, deserializadores de mensajes, ese tipo de cosas. Y lo que hace es que escribes un programa que toma como entrada alguna cadena arbitraria de bytes y haces algo con esos bytes y el fuzzer trata de hacer que se caiga. Así que si tienes algún decodificador o descompresor de imágenes, a menudo encontrará un error en el que utilizas demasiada memoria, tienes una condición de falta de memoria y tienes una vulnerabilidad DoS allí. O tal vez encuentre un error en el desbordamiento del búfer, algo así. O lo que sea, dependiendo del lenguaje en el que estés escribiendo. Los fuzzers han sido increíbles. Puedes buscar todos los CVEs y vulnerabilidades que han encontrado. Hemos estado jugando mucho con ellos en rust-lightning y tenemos los estándar de sólo asegurarse de que todos nuestros deserializadores de mensajes no se bloquean o no utilizan la memoria infinita. Pero también tenemos algunos que permiten a los nodos hacer cosas completamente arbitrarias. Así que tenemos un objetivo fuzz que ejecuta un nodo completo y puede recibir bytes en el cable. Esto le permite, literalmente, hacer cualquier cosa que otro nodo podría hacer a usted, posiblemente en un entorno de fuzzing donde el fuzzer está tratando de bloquear creativamente su programa y viene con diferentes entradas que podrían ejercer diferentes rutas de código. Los fuzzers no son tan eficientes como podrías imaginar, sólo están metiendo bytes al azar. Son mucho más inteligentes que meter bytes al azar, pero siguen metiendo bytes al azar. Y así, cuando tienes estos mensajes tan grandes, son bastante lentos y no tienes una gran cobertura de código. Hay una nueva investigación sobre cómo hacer fuzzing con una técnica llamada taint tracking. Si estás interesado, deberías buscarlo en Google, es increíblemente fascinante. Es una gran herramienta para la construcción de software de alta seguridad. Estamos explorando eso un poco en rust-lightning pero no hemos llegado tan lejos. También tenemos un objetivo fuzz más reciente que comprueba la consistencia del protocolo. Así que podemos escribir pequeños fragmentos cortos que permiten al fuzzer escribir esencialmente nuevos casos de prueba para nosotros. El fuzzer puede reordenar la entrega de mensajes para que simule la velocidad de la luz. Puede enviar pagos, recibir pagos, cosas así. Y su objetivo es encontrar inconsistencias en la máquina de estado de nuestro canal. Así que tienes dos canales en ambos lados de un nodo. Tienes un canal y tienes dos nodos y su objetivo es tratar de encontrar una manera de conseguir los dos nodos en algún estado diferente porque no deberían ser capaces, están enviando mensajes el uno al otro. Pero si de alguna manera terminan en desacuerdo sobre cuál es el estado actual, eso es claramente un error en nuestra máquina de estado. Es probablemente explotable porque probablemente hay algún caso en el que nos estamos olvidando de un HTLC o algunos fondos. Y esto ha sido increíblemente útil. Hemos copiado tal vez veinte casos de prueba de este fuzzer en nuestro conjunto de pruebas regulares y hemos encontrado una serie de errores, especialmente en nuestras cosas de pausa del canal. Así que hay una gran cantidad de trabajo realmente emocionante que hemos sido capaces de hacer en fuzzing en rust-lightning, además de sólo las pruebas de unidad estándar y pruebas de protocolo estándar. Una última cosa que quería mencionar para aquellos de ustedes que están interesados en las pruebas, el ecosistema de Rust en general es, porque es un montón de ingenieros que construyen a menudo el software de alta seguridad, una cosa que Rust tiene buenas herramientas para o que hay buenas bibliotecas para en Rust que no existen en la mayoría de los otros idiomas es una técnica llamada pruebas de mutación. Su objetivo es probar sus pruebas modificando el software real y asegurándose de que sus pruebas fallan. Si tomas tu software y cambias algunas condiciones “if” o cambias alguna inicialización por defecto de algunas variables, tu prueba debería ser capaz de detectar eso. De lo contrario, no tienes una buena cobertura de pruebas. Esto es mucho más efectivo que mirar la cobertura de rama estándar o el análisis de cobertura estándar de tu código y puede encontrar muchos más detalles que podrías haber pasado por alto en las pruebas y cosas para las que deberías añadir pruebas. Así que este es el trabajo futuro que nos gustaría hacer en rust-lightning. Si estás interesado en escribir pruebas de última generación, ven a hablar conmigo. Nos encantaría contar con colaboradores. Así que con eso me dijeron que tengo que mencionar que Chaincode está ejecutando otro programa de residencia. Hemos tenido un gran éxito con estos en el pasado. La mayoría de la gente termina consiguiendo un trabajo en algún lugar en el espacio. Si usted está realmente interesado en Bitcoin y quiere conseguir realmente profundo en el nitty gritty de la ingeniería de protocolo tanto en Bitcoin y cómo todo funciona y cómo la gente piensa en ello. Y Lightning y otras cosas. Usted debe aplicar. Es residency.chaincode.com. Son unas dos semanas de curso intensivo donde habrá una tonelada de charlas de grandes ponentes. Yo y algunas de las otras personas de Chaincode y tenemos gente que viene a la ciudad sólo para hablar con usted. Vamos a hacerlo un poco diferente esta vez y va a haber un montón de tiempo de proyecto para que puedas pasar el rato en Nueva York con nosotros con algunos grandes mentores, algunas de las personas más inteligentes en el ecosistema Bitcoin te ayudarán con cualquier proyecto que quieras trabajar, ya sea rust-lightning o BetterHash o contribuir a Bitcoin Core u otras implementaciones Lightning o cualquier proyecto genial que quieras hacer, puedes venir a pasar el rato con gente brillante y hacer eso.
PREGUNTAS Y RESPUESTAS
P - Me pregunto sobre todas las actualizaciones que se avecinan en la versión 1 de SegWit y cómo eso cambiará a Rust. ¿Cómo planean actualizar la biblioteca Rust para manejar todos los cambios que se avecinan?
R - Con rust-lightning no siendo producción todavía significa que no podemos molestarnos en dar soporte a cosas de la vieja escuela e incluso ignorando la versión 1 de SegWit, con los cambios de Lightning 1.1, algunos de esos cambios los quiero tener en rust-lightning y soportados en la red antes de que nadie empiece a usar rust-lightning en producción porque simplificará un montón de cosas sobre la interconexión y se asegurará de que es realmente fácil usar rust-lightning y no tiene desacuerdos de tasas. También, obviamente, eltoo y demás harán, con suerte, que las torres de vigilancia sean órdenes de magnitud más simples y que podamos desechar el código antiguo porque nadie lo está usando todavía.