En Solana, un contrato inteligente se llama programa. Un programa es una cuenta sin estado que contiene código ejecutable. Este código está organizado en funciones llamadas instrucciones. Los usuarios interactúan con un programa enviando una transacción que contiene una o más instrucciones. Una transacción puede incluir instrucciones de múltiples programas.
Cuando se despliega un programa, Solana usa LLVM para compilarlo en formato ejecutable y enlazable (ELF). El archivo ELF contiene el binario del programa en formato de bytecode de Solana (sBPF) y se guarda en cadena en una cuenta ejecutable.
sBPF es la versión personalizada de Solana del bytecode eBPF.
Escribir programas
La mayoría de los programas están escritos en Rust, con dos enfoques comunes de desarrollo:
- Anchor: Anchor es un framework diseñado para el desarrollo rápido y sencillo en Solana. Utiliza macros de Rust para reducir el código repetitivo, lo que lo hace ideal para principiantes.
- Rust nativo: Escribe programas en Rust sin utilizar ningún framework. Este enfoque ofrece más flexibilidad pero conlleva mayor complejidad.
Actualizar programas
Para
modificar
un programa existente, una cuenta debe ser designada como la
autoridad de actualización.
(Normalmente la misma cuenta que originalmente
desplegó el programa.) Si la autoridad de
actualización es revocada y establecida como None, el programa ya no podrá ser
actualizado.
Verificar programas
Solana admite compilaciones verificables, que permiten a los usuarios comprobar si el código en cadena de un programa coincide con su código fuente público. El framework Anchor proporciona soporte integrado para crear una compilación verificable.
Para verificar si un programa existente está verificado, busca su ID de programa en el Solana Explorer. Alternativamente, puedes usar el Solana Verifiable Build CLI de Ellipsis Labs para verificar independientemente los programas on-chain.
Programas integrados
El System Program
El System Program es la única cuenta que puede crear nuevas cuentas. Por defecto, todas las cuentas nuevas son propiedad del System Program, aunque muchas se asignan a un nuevo propietario al momento de su creación. El System Program realiza las siguientes funciones clave:
| Función | Descripción |
|---|---|
| Creación de nuevas cuentas | Solo el System Program puede crear nuevas cuentas. |
| Asignación de espacio | Establece la capacidad en bytes para el campo de datos de cada cuenta. |
| Asignación de propiedad del programa | Una vez que el System Program crea una cuenta, puede reasignar el propietario del programa designado a una cuenta de programa diferente. Así es como los programas personalizados toman propiedad de las nuevas cuentas creadas por el System Program. |
| Transferir SOL | Transfiere lamports (SOL) desde cuentas del sistema a otras cuentas. |
La dirección del system program es 11111111111111111111111111111111.
Programas loader
Cada programa es propiedad de otro: su loader. Los loaders se utilizan para desplegar, redesplegar, actualizar o cerrar programas. También se usan para finalizar un programa y transferir la autoridad del programa.
Actualmente existen cinco programas loader, como se muestra en la tabla a continuación.
| Loader | ID del programa | Notas | Enlace de instrucciones |
|---|---|---|---|
| native | NativeLoader1111111111111111111111111111111 | Posee los otros cuatro loaders | — |
| v1 | BPFLoader1111111111111111111111111111111111 | Las instrucciones de gestión están deshabilitadas, pero los programas aún se ejecutan | — |
| v2 | BPFLoader2111111111111111111111111111111111 | Las instrucciones de gestión están deshabilitadas, pero los programas aún se ejecutan | Instrucciones |
| v3 | BPFLoaderUpgradeab1e11111111111111111111111 | Los programas pueden actualizarse después del despliegue. El ejecutable del programa se almacena en una cuenta de datos de programa separada | Instrucciones |
| v4 | LoaderV411111111111111111111111111111111111 | En desarrollo (no publicado) | Instrucciones |
Los programas desplegados con loader-v3 o loader-v4 pueden ser modificables después del despliegue, según lo determine su autoridad de actualización.
Cuando se despliega un nuevo programa, se utilizará la última versión del loader de forma predeterminada.
Programas precompilados
Además de los programas loader, Solana proporciona los siguientes programas precompilados.
Verificar firma ed25519
El programa ed25519 se utiliza para verificar una o más firmas ed25519.
| Programa | ID del programa | Descripción | Instrucciones |
|---|---|---|---|
| Programa Ed25519 | Ed25519SigVerify111111111111111111111111111 | Verifica firmas ed25519. Si alguna firma falla, se devuelve un error. | Instrucciones |
El programa ed25519 procesa una instrucción. El primer u8 de la instrucción
contiene un contador del número de firmas a verificar, seguido de un solo byte
de relleno. Después de eso, se serializa la siguiente estructura, una por cada
firma a verificar.
struct Ed25519SignatureOffsets {signature_offset: u16, // offset to ed25519 signature of 64 bytessignature_instruction_index: u16, // instruction index to find signaturepublic_key_offset: u16, // offset to public key of 32 bytespublic_key_instruction_index: u16, // instruction index to find public keymessage_data_offset: u16, // offset to start of message datamessage_data_size: u16, // size of message datamessage_instruction_index: u16, // index of instruction data to get message data}
process_instruction() {for i in 0..count {// i'th index values referenced:instructions = &transaction.message().instructionsinstruction_index = ed25519_signature_instruction_index != u16::MAX ? ed25519_signature_instruction_index : current_instruction;signature = instructions[instruction_index].data[ed25519_signature_offset..ed25519_signature_offset + 64]instruction_index = ed25519_pubkey_instruction_index != u16::MAX ? ed25519_pubkey_instruction_index : current_instruction;pubkey = instructions[instruction_index].data[ed25519_pubkey_offset..ed25519_pubkey_offset + 32]instruction_index = ed25519_message_instruction_index != u16::MAX ? ed25519_message_instruction_index : current_instruction;message = instructions[instruction_index].data[ed25519_message_data_offset..ed25519_message_data_offset + ed25519_message_data_size]if pubkey.verify(signature, message) != Success {return Error}}return Success}
Verificar recuperación secp256k1
El programa secp256k1 se utiliza para verificar operaciones de recuperación de clave pública secp256k1.
| Programa | ID del programa | Descripción | Instrucciones |
|---|---|---|---|
| Programa Secp256k1 | KeccakSecp256k11111111111111111111111111111 | Verifica operaciones de recuperación de clave pública secp256k1 (ecrecover). | Instrucciones |
El programa secp256k1 procesa una instrucción. El primer byte de la instrucción contiene un contador del número de claves públicas a verificar. Después de eso, se crea la siguiente estructura una vez por cada clave pública, luego se serializa y se añade a los datos de instrucción.
struct Secp256k1SignatureOffsets {secp_signature_offset: u16, // offset to [signature,recovery_id] of 64+1 bytessecp_signature_instruction_index: u8, // instruction index to find signaturesecp_pubkey_offset: u16, // offset to ethereum_address pubkey of 20 bytessecp_pubkey_instruction_index: u8, // instruction index to find pubkeysecp_message_data_offset: u16, // offset to start of message datasecp_message_data_size: u16, // size of message datasecp_message_instruction_index: u8, // instruction index to find message data}
process_instruction() {for i in 0..count {// i'th index values referenced:instructions = &transaction.message().instructionssignature = instructions[secp_signature_instruction_index].data[secp_signature_offset..secp_signature_offset + 64]recovery_id = instructions[secp_signature_instruction_index].data[secp_signature_offset + 64]ref_eth_pubkey = instructions[secp_pubkey_instruction_index].data[secp_pubkey_offset..secp_pubkey_offset + 20]message_hash = keccak256(instructions[secp_message_instruction_index].data[secp_message_data_offset..secp_message_data_offset + secp_message_data_size])pubkey = ecrecover(signature, recovery_id, message_hash)eth_pubkey = keccak256(pubkey[1..])[12..]if eth_pubkey != ref_eth_pubkey {return Error}}return Success}
Esto permite al usuario especificar cualquier dato de instrucción en la transacción para datos de firma y mensaje. Al especificar una sysvar de instrucciones especial, también se puede recibir datos de la transacción misma.
El costo de la transacción contará el número de firmas a verificar multiplicado por el multiplicador de costo de verificación de firma.
El programa secp256r1 se utiliza para verificar hasta 8 firmas secp256r1.
| Programa | ID del programa | Descripción | Instrucciones |
|---|---|---|---|
| Programa Secp256r1 | Secp256r1SigVerify1111111111111111111111111 | Verifica hasta 8 firmas secp256r1. Toma una firma, clave pública y mensaje. Devuelve error si alguna falla. | Instrucciones |
El programa secp256r1 procesa una instrucción. El primer u8 de la instrucción
es un contador del número de firmas a verificar, seguido de un solo byte de
relleno. Después de eso, se crea la siguiente estructura para cada firma, luego
se serializa y se añade a los datos de instrucción.
struct Secp256r1SignatureOffsets {signature_offset: u16, // offset to compact secp256r1 signature of 64 bytessignature_instruction_index: u16, // instruction index to find signaturepublic_key_offset: u16, // offset to compressed public key of 33 bytespublic_key_instruction_index: u16, // instruction index to find public keymessage_data_offset: u16, // offset to start of message datamessage_data_size: u16, // size of message datamessage_instruction_index: u16, // index of instruction data to get message data}
Se imponen valores S bajos para todas las firmas para evitar la maleabilidad accidental de la firma.
process_instruction() {if data.len() < SIGNATURE_OFFSETS_START {return Error}num_signatures = data[0] as usizeif num_signatures == 0 || num_signatures > 8 {return Error}expected_data_size = num_signatures * SIGNATURE_OFFSETS_SERIALIZED_SIZE + SIGNATURE_OFFSETS_STARTif data.len() < expected_data_size {return Error}for i in 0..num_signatures {offsets = parse_signature_offsets(data, i)signature = get_data_slice(data, instruction_datas, offsets.signature_instruction_index, offsets.signature_offset, SIGNATURE_SERIALIZED_SIZE)if s > half_curve_order {return Error}pubkey = get_data_slice(data, instruction_datas, offsets.public_key_instruction_index, offsets.public_key_offset, COMPRESSED_PUBKEY_SERIALIZED_SIZE)message = get_data_slice(data, instruction_datas, offsets.message_instruction_index, offsets.message_data_offset, offsets.message_data_size)if !verify_signature(signature, pubkey, message) {return Error}}return Success}
Programas principales
Los programas en la lista a continuación proporcionan la funcionalidad central de la red.
| Programa | ID del programa | Descripción | Instrucciones |
|---|---|---|---|
| System | 11111111111111111111111111111111 | Crea nuevas cuentas, asigna datos de cuenta, asigna cuentas a programas propietarios, transfiere lamports desde cuentas propiedad del programa System y paga tarifas de transacción | SystemInstruction |
| Vote | Vote111111111111111111111111111111111111111 | Crea y gestiona cuentas que rastrean el estado de votación y recompensas del validador | VoteInstruction |
| Stake | Stake11111111111111111111111111111111111111 | Crea y gestiona cuentas que representan stake y recompensas para delegaciones a validadores | StakeInstruction |
| Config | Config1111111111111111111111111111111111111 | Añade datos de configuración a la cadena, seguidos de la lista de claves públicas que pueden modificarla. A diferencia de otros programas, el programa Config no define instrucciones individuales. Solo tiene una instrucción implícita: "store". Sus datos de instrucción son un conjunto de claves que controlan el acceso a la cuenta y los datos almacenados en ella | ConfigInstruction |
| Compute Budget | ComputeBudget111111111111111111111111111111 | Establece límites y precios de unidades de cómputo para transacciones, permitiendo a los usuarios controlar recursos de cómputo y tarifas de priorización | ComputeBudgetInstruction |
| Address Lookup Table | AddressLookupTab1e1111111111111111111111111 | Gestiona tablas de búsqueda de direcciones, que permiten a las transacciones referenciar más cuentas de las que cabrían en la lista de cuentas de la transacción | ProgramInstruction |
| ZK ElGamal Proof | ZkE1Gama1Proof11111111111111111111111111111 | Proporciona verificación de pruebas de conocimiento cero para datos cifrados con ElGamal | — |
Is this page helpful?