Puntos Clave del Runtime Sealevel
Sealevel es el runtime paralelo de Solana para programas en cadena: programa el trabajo a partir del acceso declarado a las cuentas, mide el cómputo y mantiene la lógica del programa separada del estado duradero.
Esta página es el mapa conceptual para Programas y Runtime Sealevel: bytecode ejecutable, el punto de entrada del SVM, bloqueos de cuentas, concurrencia, presupuestos de cómputo y cargadores en Agave 4.1.1.
Resumen
- Los programas de Solana son ejecutables sin estado; Sealevel los ejecuta contra las cuentas que la transacción listó por adelantado, bloqueando esas cuentas para que el trabajo no conflictivo pueda proceder en paralelo.
- Por Qué Importa: Casi todas las decisiones de diseño (PDAs, forma de las instrucciones, límites de CU, actualizaciones) siguen cómo el runtime bloquea las cuentas y mide el cómputo, no cómo almacenarías datos dentro de un contrato.
- Conceptos Clave: cuenta de programa ejecutable, sBPF / SVM, punto de entrada, AccountMeta, bloqueos de lectura/escritura, unidades de cómputo (CU), cargador actualizable / ProgramData.
- Cuándo Usar Este Modelo: Diseñar layouts de estado, razonar sobre el rendimiento bajo contención, depurar cuentas faltantes o fallos de CU, o enseñar la ejecución de Solana a compañeros de equipo acostumbrados a runtimes secuenciales.
- Limitaciones / Compensaciones: El paralelismo no es automático: una cuenta escribible compartida serializa el trabajo, y cada camino pesado cuesta CU dentro de un presupuesto de transacción finito.
- Temas Relacionados: Conceptos Básicos de Programas, El SVM y sBPF, Ejecución Paralela de Sealevel, Bloqueos de Cuentas y Conflictos, Unidades de Cómputo y Presupuestos, Programas Sin Estado.
Fundamentos
Un programa en Solana es una cuenta ejecutable: sus datos son bytecode que el runtime tiene permiso de ejecutar, no registros de aplicación que mutas instrucción por instrucción.
El estado duradero vive en otras cuentas que el programa posee (o puede leer). El binario no incrusta una base de datos creciente de usuarios, saldos o mapeos.
Escribes lógica en Rust (o en otro lenguaje soportado), compilas a sBPF (Solana BPF), y despliegas el objeto compartido para que los validadores lo carguen.
El SVM (Solana Virtual Machine) en los validadores Agave ejecuta ese sBPF, hace cumplir las reglas de propiedad, mide el cómputo y atiende las llamadas al sistema.
Una instrucción nombra un ID de programa, una lista de cuentas y un slice de bytes de datos de instrucción opaco.
El punto de entrada del programa es la única función que el runtime llama para cada instrucción a ese programa.
En su forma nativa, el punto de entrada recibe aproximadamente program_id, un slice de valores AccountInfo, y los datos de la instrucción. La macro #[program] de Anchor genera ese punto de entrada y despacha según un discriminador de 8 bytes a tus manejadores.
Cada instrucción debe declarar AccountMeta para cada cuenta que el runtime tocará: clave pública, is_signer, y is_writable.
Esas flags son solicitudes de bloqueo que Sealevel usa antes de que se ejecute cualquier bytecode, no sugerencias opcionales del lado del cliente.
Mecánicas e Interacciones
La ejecución comienza fuera de tu programa: se ensambla una transacción con una o más instrucciones, cada una listando el ID del programa, las cuentas y los datos, luego se firma y se envía con un blockhash reciente.
El runtime valida las firmas, el saldo del pagador de tarifas, y que cada cuenta que aparece en cualquier instrucción esté presente en la lista de cuentas de la transacción con metadatos consistentes.
Antes de programar, Sealevel deriva bloqueos de esas metadatos: una cuenta escribible necesita un bloqueo de escritura exclusivo; una cuenta de solo lectura necesita un bloqueo de lectura compartido.
Múltiples transacciones pueden tener bloqueos de lectura en la misma cuenta concurrentemente.
Un bloqueo de escritura excluye a otros escritores y lectores en la misma cuenta durante la duración del trabajo conflictivo.
Esa regla produce el comportamiento central de programación: las transacciones cuyos conjuntos de cuentas bloqueadas no entran en conflicto pueden ejecutarse en paralelo; los solapamientos de escritura-escritura y escritura-lectura deben serializarse.
Claves de cuenta:
A = PDA de posición de Alice (escribible en las tx de Alice)
B = PDA de posición de Bob (escribible en las tx de Bob)
G = Bóveda global (escribible cuando alguien la toca)
C = Configuración (solo lectura en ambos diseños)
Bloqueos disjuntos - pueden ejecutarse concurrentemente:
Tx1: write(A), read(C)
Tx2: write(B), read(C)
-> bloqueos: A exclusivo, B exclusivo, C compartido -> sin conflicto
Bloqueos solapados - deben serializarse:
Tx3: write(G), write(A), read(C)
Tx4: write(G), write(B), read(C)
-> ambos necesitan G exclusivo -> Tx3 y Tx4 no pueden ejecutarse en paralelo
Dentro de una transacción programada, las instrucciones se ejecutan en orden; dentro de una instrucción, el SVM carga el programa, llama al punto de entrada y pasa solo las cuentas que esa instrucción listó.
Tu manejador puede leer datos de cuentas, escribir solo cuentas que posea (y que fueron marcadas como escribibles), transferir lamports bajo las reglas habituales, y emitir CPIs a otros programas - pero cada cuenta que una CPI necesita debe estar ya en el conjunto declarado de la transacción.
Mientras se ejecuta el punto de entrada, el runtime mide las unidades de cómputo (CU). Las llamadas al sistema, el registro, la deserialización y la aritmética consumen del presupuesto de la transacción.
En Solana moderno (incluyendo Agave 4.1.1), el presupuesto de cómputo de transacción por defecto es de aproximadamente 1,400,000 CU a menos que una instrucción de Presupuesto de Cómputo aumente (o disminuya) el límite dentro de los límites del protocolo.
Si algún camino excede el presupuesto restante, la transacción falla y los cambios de estado de esa transacción no se confirman.
CU mide el trabajo permitido; las tarifas de prioridad influyen en la inclusión bajo carga - perillas relacionadas, trabajos diferentes.
Después del éxito, las actualizaciones de cuentas se confirman bajo los bloqueos ya mantenidos; las transacciones fallidas liberan los bloqueos sin aplicar esas escrituras.
Las actualizaciones se sitúan junto a la ejecución, no dentro del estado de la aplicación. Con el BPF Upgradeable Loader, la cuenta del ID del programa apunta a una cuenta ProgramData que contiene el bytecode.
Una autoridad de actualización (si está configurada) puede desplegar un nuevo .so en ProgramData; borrar esa autoridad congela la ruta de actualización del cargador.
Dado que los programas son sin estado, las actualizaciones intercambian lógica sin migrar el almacenamiento fuera del binario - las cuentas de datos permanecen, por lo que el nuevo código debe mantenerse compatible con el layout o enviar una migración explícita.
Consideraciones Avanzadas y Aplicaciones
La decisión de diseño de mayor apalancamiento bajo Sealevel es qué marcas como escribible.
Una única cuenta escribible global - una configuración de "mutex", un ledger compartido, un contador global que cada usuario debe tocar - fuerza a cada transacción contendiente a un solo archivo, sin importar cuán eficiente sea el sBPF.
Fragmentar el estado para que cada usuario (o cada orden, posición o sesión) tenga su propio PDA mantiene la mayoría de las transacciones en claves disjuntas para que el programador pueda ejecutarlas juntas.
| Diseño | Cuentas escribibles por acción de usuario | Paralelismo bajo carga | Cuándo encaja | Costo de equivocarse |
|---|---|---|---|---|
| PDAs por usuario / por entidad | Usualmente el PDA de ese usuario (+ cuentas token según sea necesario) | Alto - diferentes usuarios raramente bloquean las mismas claves | Perfiles de usuario, posiciones, inventarios, sesiones | Ligeramente más cuentas para pasar y crear |
| Tablas fragmentadas (muchos PDAs por clave de fragmento) | Un PDA de fragmento entre muchos | Alto si la carga se distribuye entre fragmentos | Índices de alto rendimiento, libros de órdenes, colas | Las claves de fragmento "calientes" aún serializan esa porción del tráfico |
| Configuración global (solo lectura en ruta activa) | Ninguna para la configuración si solo se lee | Los lectores comparten el bloqueo de configuración | Parámetros, tasas de tarifas, flags de características | Marcar la configuración como escribible en cada tx mata el paralelismo |
| Cuenta mutex global (siempre escribible) | La misma cuenta global para todos | Bajo - esencialmente secuencial en esa clave | Operaciones raras de administración, invariantes globales verdaderas que deben serializarse | El techo de rendimiento equivale a un escritor a la vez |
| Híbrido: ruta activa fragmentada, ruta inactiva global | PDA de usuario en ruta activa; global solo en administración/liquidación | La ruta activa escala; la ruta de administración serializa intencionalmente | Mercados que se liquidan contra una bóveda compartida según un horario | Poner accidentalmente la bóveda en la ruta activa |
Prefiere solo lectura siempre que no mutes: un PDA de configuración compartido marcado como solo lectura permite que muchas transacciones mantengan bloqueos de lectura concurrentes.
Mantén los conjuntos escribibles mínimos y predecibles para que los clientes puedan construir listas de cuentas y el grafo de bloqueos se mantenga disperso.
Observa las CU de la misma manera que observas los bloqueos: la deserialización de cuentas grandes, el registro verboso msg!, y los bucles sin límites queman presupuesto y pueden empujar caminos ordinarios hacia el techo por defecto de ~1,400,000 CU.
Solicita un límite más alto con una instrucción de Presupuesto de Cómputo cuando la simulación muestre que lo necesitas; aún así optimiza la ruta activa para no pagar tarifas de prioridad por desperdicio.
Piensa en los cargadores en producción: retén la autoridad de actualización solo mientras la necesites, usa compilaciones verificables, y trata las actualizaciones de ProgramData como un proceso de control de cambios - el compromiso de la autoridad es un riesgo de reescritura completa del código.
Al probar en pilas alineadas con Agave 4.1.1 (CLI 3.0.10, Anchor 0.32.1, LiteSVM 0.6.x, Surfpool 0.12.0), ejercita los casos de CU y cuentas contendidas antes de que el tráfico de mainnet lo haga.
Conceptos Erróneos Comunes
- "Los programas mantienen el estado de la aplicación como los contratos EVM." Los programas contienen bytecode ejecutable; el estado de la aplicación vive en cuentas separadas que el programa posee - ver Programas Sin Estado.
- "Sealevel paraleliza cada transacción automáticamente." Solo las transacciones con conjuntos de bloqueos no conflictivos se ejecutan juntas; las cuentas escribibles compartidas fuerzan la serialización.
- "Si dos transacciones solo leen la misma cuenta, deben esperar." Múltiples lectores pueden compartir un bloqueo de lectura; los conflictos aparecen cuando al menos un lado necesita un bloqueo de escritura en la misma clave.
- "El programa puede obtener cualquier cuenta que quiera en tiempo de ejecución." Cada cuenta debe aparecer en la lista declarada de la transacción con flags correctos de firmante/escribible antes de que comience la ejecución.
- "Exceder el cómputo solo falla una instrucción." El cómputo se mide contra el presupuesto de la transacción; el agotamiento falla la transacción y revierte sus efectos.
- "El CU por defecto es ilimitado hasta que establezco un presupuesto." Hay un techo por transacción por defecto (aproximadamente 1,400,000 CU en Solana moderno); puedes solicitar un límite diferente dentro de los límites del protocolo a través de instrucciones de Presupuesto de Cómputo.
- "is_writable es opcional si mi código solo escribe a veces." Las flags de metadatos definen bloqueos y autorización para escrituras; declarar insuficientemente como escribible o faltar cuentas causa fallos en tiempo de ejecución o impide mutaciones deseadas.
- "Actualizar el programa reescribe los datos de la cuenta del usuario." El cargador actualizable intercambia bytecode en ProgramData; las cuentas de datos existentes permanecen como están a menos que envíes lógica de migración.
- "CPI me permite descubrir cuentas de callee dinámicamente sin listarlas." CPI aún requiere que todas las cuentas necesarias hayan sido proporcionadas en la lista de cuentas de la transacción externa.
- "Una cuenta grande es más simple y tan rápida como cualquier otra." Puede ser más simple de codificar, pero se convierte en un mutex global bajo Sealevel y limita el rendimiento a un escritor a la vez.
Preguntas Frecuentes
¿Qué es exactamente un programa de Solana bajo Sealevel?
Una cuenta ejecutable cuyos datos son bytecode sBPF que el SVM puede ejecutar. Se invoca mediante instrucciones que nombran su ID de programa y pasan cuentas más datos de instrucción.
¿Dónde vive el estado de mi aplicación si el programa no tiene estado?
En cuentas de datos propiedad de tu programa (a menudo PDAs). El programa lee y escribe esas cuentas cuando se pasan y se marcan apropiadamente.
¿Qué recibe el punto de entrada?
El ID del programa, un slice de infos de cuentas para las cuentas listadas en la instrucción, y los bytes de datos de la instrucción. Frameworks como Anchor 0.32.1 generan este punto de entrada y despachan a manejadores tipados.
¿Por qué los clientes deben declarar is_signer e is_writable?
Esas flags de AccountMeta le dicen al runtime quién autorizó la transacción y qué cuentas necesitan bloqueos de escritura exclusivos frente a bloqueos de lectura compartidos. Flags incorrectas causan fallos o privilegios de escritura faltantes.
¿Cuándo pueden ejecutarse dos transacciones al mismo tiempo?
Cuando sus bloqueos requeridos no entran en conflicto - típicamente cuando tocan conjuntos escribibles disjuntos y cualquier cuenta compartida es de solo lectura para todos los lectores concurrentes. Ver Ejecución Paralela de Sealevel.
¿Qué conflictos de bloqueo fuerzan la serialización?
Escritura-escritura en la misma cuenta, y escritura-lectura en la misma cuenta. Dos lectores puros de la misma cuenta no necesitan serializarse entre sí. Detalles en Bloqueos de Cuentas y Conflictos.
¿Cuál es el presupuesto de cómputo por defecto que debo asumir?
En Solana moderno, incluyendo Agave 4.1.1, planifica alrededor de un presupuesto de cómputo de transacción por defecto de aproximadamente 1,400,000 CU a menos que las instrucciones de Presupuesto de Cómputo establezcan un límite diferente dentro de los límites del protocolo.
¿Qué sucede si mi instrucción usa demasiadas unidades de cómputo?
La transacción falla con un error de presupuesto de cómputo y no confirma los cambios de estado de esa transacción. Simula, mide los logs (consumed), y optimiza o solicita un límite más alto. Ver Unidades de Cómputo y Presupuestos.
¿Cómo se relacionan Rust, sBPF y el SVM?
Compilas Rust a sBPF con la cadena de herramientas de Solana/Agave (cargo build-sbf / compilación de Anchor). Los validadores ejecutan ese bytecode en el SVM bajo las reglas de programación y medición de Sealevel. Ver El SVM y sBPF.
¿Cómo funcionan los programas actualizables?
El BPF Upgradeable Loader mantiene una cuenta de programa que apunta a ProgramData que contiene el bytecode. Una autoridad de actualización puede desplegar nuevo bytecode; eliminar la autoridad congela esa ruta de actualización.
¿La actualización cambia las direcciones de mis PDAs?
No. Las direcciones de PDA derivan del ID del programa y las semillas. El ID del programa permanece igual a través de las actualizaciones del mismo programa desplegado; solo el bytecode en ProgramData cambia.
¿Cómo debo diseñar las cuentas para el máximo paralelismo?
Dale a cada actor o entidad independiente su propia cuenta escribible (comúnmente un PDA), mantén las cuentas globales de solo lectura en las rutas activas, y evita una única cuenta escribible que todos los usuarios deban tocar.
¿Puedo mutar una cuenta que mi programa no posee?
No para escrituras de datos arbitrarias - solo el programa propietario puede modificar los datos de una cuenta. Otros programas interactúan a través de CPI en el propietario (por ejemplo, SPL Token) con las cuentas y firmantes correctos.
¿Las CPIs obtienen un presupuesto de cómputo separado?
Las CPIs consumen CU del mismo presupuesto de transacción. Las llamadas anidadas aún consumen del pool compartido; las pilas de CPI profundas o pesadas necesitan presupuestación y simulación.
¿Cómo cambia este modelo bajo Alpenglow u otro trabajo de consenso?
La latencia de confirmación puede cambiar, pero el modelo mental del programa - cuentas declaradas, bloqueos, ejecutables sin estado, medición de CU - sigue siendo Sealevel como se describe aquí.
Relacionado
- Conceptos Básicos de Programas - qué es un programa y cómo se invoca
- El SVM y sBPF - objetivo de compilación y máquina virtual
- Ejecución Paralela de Sealevel - programación de transacciones no conflictivas
- Bloqueos de Cuentas y Conflictos - reglas de bloqueo de lectura/escritura en detalle
- Unidades de Cómputo y Presupuestos - medición, límites y optimización
- Programas Sin Estado - por qué la lógica y el estado se mantienen separados
- El Punto de Entrada del Programa - punto de entrada, slice de cuentas, datos de instrucción
- Cargadores de Programas y Capacidad de Actualización - cargador actualizable y ProgramData
Versiones de la Pila: Esta página fue escrita para Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0, y LiteSVM 0.6.x.