Conceptos del entorno
El entorno del contrato es una interfaz que define las facilidades -- objetos, funciones, fuentes de datos, etc. -- disponibles para los contratos.
Host y Huésped
Como una interfaz, el entorno tiene dos lados, a los que nos referimos como el entorno host y el entorno huésped. El código en el entorno host implementa la interfaz del entorno; el código en el entorno huésped usa la interfaz del entorno.
El entorno host es proporcionado por un conjunto conocido de crates de Rust, compilados una vez en stellar-core (o el SDK). Varios contratos interactúan con el mismo entorno host, y el entorno host tiene acceso a cualquier instalación de su sistema operativo contenedor: archivos, redes, memoria, etc.
En contraste, un nuevo entorno huésped se establece para cada invocación de cada contrato inteligente. Cada contrato ve una única interfaz de entorno, y solo puede llamar a funciones proporcionadas por la interfaz del entorno. En otras palabras, el entorno huésped es un espacio aislado para ejecutar código arbitrario dentro de parámetros seguros.
WebAssembly
El entorno huésped on-chain está aislado dentro de una máquina virtual WebAssembly (Wasm) ("VM"). Esto significa que el código del contrato desplegado se compila en bytecode Wasm en lugar de código de máquina nativo. El entorno host incluye un intérprete para la VM, y se instancia una nueva VM de corta duración para cada llamada a un contrato, ejecutando el bytecode del contrato y luego saliendo.
El uso de una VM ayuda a proporcionar seguridad contra cualquier posible mal comportamiento del código huésped, tanto para el host como para otros entornos huéspedes, así como garantizar la portabilidad del código huésped entre hosts que se ejecutan en diferentes tipos de hardware.
Al desarrollar y probar código de contrato fuera de la cadena, es posible compilar el código del contrato a código de máquina nativo en lugar de bytecode Wasm, y ejecutar pruebas y depurar contratos contra una copia local del entorno host vinculándose directamente a él, en lugar de ejecutar dentro de una VM. Esta configuración se ejecuta mucho más rápido y proporciona una mejor información de depuración, pero solo es posible localmente, fuera de la cadena. Los contratos desplegados on-chain son siempre Wasm.
WebAssembly es una VM de bajo nivel relativamente, lo que significa que no proporciona un conjunto muy rico de operaciones estándar o "incorporadas". En contraste con VMs como la JVM, no tiene recolector de basura (ni siquiera un asignador de memoria), no tiene instalaciones de E/S, no hay estructuras de datos estándar como listas, arrays, mapas o cadenas, y no hay conceptos de objetos o tipos además de los tipos de máquina básicos como enteros de 32 y 64 bits.
Como resultado, los programas compilados en bytecode Wasm a menudo enfrentan un dilema: si quieren funcionalidad estándar rica, a menudo deben incluir una copia de todo el "código de soporte" para esa funcionalidad dentro de ellos mismos. Pero si lo hacen, aumentan drásticamente su tamaño de código, lo que incurre en costos y limita el rendimiento. Además, incluir dicho código de soporte limita su capacidad para interoperar con otros programas que pueden incluir diferentes códigos de soporte incompatibles.
La solución a este dilema es que el entorno mismo proporcione código de soporte para una funcionalidad estándar rica, en forma de objetos y funciones del host que el código huésped puede utilizar por referencia. Cada contrato se refiere a la misma funcionalidad implementada en el host, asegurando un tamaño de código mucho más pequeño, un rendimiento más alto y una mayor interoperabilidad entre contratos. Esto es lo que hace Soroban.
Objetos y funciones del host
La funcionalidad estándar compartida disponible para todo el código huésped del contrato se proporciona a través de la interfaz del entorno en términos de objetos y funciones del host.
El entorno admite un pequeño número de tipos de objetos del host que cubren estructuras de datos como vectores, mapas, blobs binarios, direcciones, cadenas y enteros grandes. Los objetos del host son todos inmutables, están asignados y residen dentro del entorno host, y solo están disponibles en el entorno huésped por referencia. El código huésped se refiere a los objetos del host mediante identificadores de valor entero.
También hay un conjunto de funciones del host un poco más grande que actúa sobre los objetos del host: creando, modificando, inspeccionando y manipulándolos. Algunas funciones del host permiten copiar bloques de datos binarios dentro y fuera de la memoria de la VM del huésped, y algunas funciones del host realizan operaciones criptográficas sobre los objetos del host.
También hay funciones del host para interactuar con componentes seleccionados del entorno host más allá del repertorio de objetos del host, como leer y escribir entradas del ledger, emitir eventos, llamar a otros contratos y acceder a información sobre el contexto de la transacción en el que se está ejecutando el código huésped.
Serialización
Los objetos del host pueden ser pasados (por identificador) directamente a rutinas de almacenamiento o entre contratos colaboradores. No necesita existir código de serialización o deserialización en el huésped: el host sabe cómo serializar y deserializar todos sus tipos de objeto y lo hace de manera transparente siempre que sea necesario.
Valores y tipos
Todas las funciones del host pueden aceptar como argumentos y devolver valores de, como máximo, el limitado repertorio de tipos de máquina de la VM Wasm. Para simplificar las cosas, Soroban limita aún más todas las funciones del host a pasar y devolver valores dentro de una única forma especializada de enteros de 64 bits llamada "valor" o "el tipo de valor". A través de un empaquetado cuidadoso de bits, el tipo de valor puede codificar cualquiera de varios tipos separados más significativos para los usuarios que simplemente "enteros".
Específicamente, el tipo de valor puede codificar directamente enteros pequeños (hasta 56 bits), pero también verdadero y falso booleanos, enteros de 32 bits con signo o sin signo, identificadores de objetos del host tipados, códigos de error tipados, símbolos pequeños (hasta 9 caracteres alfanuméricos latinos), o un valor único vacío. Los bits individuales en un valor se asignan a etiquetar y cambiar entre estos casos dinámicamente, y las funciones u objetos del host que requieren casos específicos pueden rechazar valores de otros casos.
Dado que el tipo de valor puede contener un identificador de un objeto del host, cualquier objeto contenedor que puede contener el tipo de valor puede, de hecho, contener cualquier objeto. Por lo tanto, los tipos de mapa y vector del host -- estructuras de datos contenedoras -- se definen meramente como contenedores para el tipo de valor, donde el caso específico de cada valor puede variar de contenedor a contenedor o incluso entre los elementos de un contenedor. De esta manera, los tipos de contenedor del host son más similares a los contenedores de lenguajes de tipos dinámicos como JavaScript o Python. El SDK también proporciona envoltorios estáticos y uniformemente tipados cuando se desea, prohibiendo que valores fuera del caso designado se agreguen al contenedor.