NOVO: Helius adquire a Light Protocol
O modelo de programação da Solana
Blog/Fundamentos

O modelo de programação da Solana: uma introdução ao desenvolvimento na Solana

Developer Experience Engineer0xIchigo no X0xIchigo no LinkedIn0xIchigo no GitHub
24 min de leitura

Sobre o que é este artigo?

A abordagem da Solana à computação descentralizada se baseia em um princípio simples: tudo é armazenado em sua própria região de memória, conhecida como conta. A Solana funciona como um armazenamento global de chave/valor, no qual as chaves públicas atuam como identificadores exclusivos das contas correspondentes. As contas são a base da Solana porque armazenam o estado; elas contêm desde programas até saldos de tokens. As transações são usadas para atualizar contas e refletir mudanças de estado.

Neste artigo, exploramos as complexidades da arquitetura da Solana. Começamos com uma visão geral dos clusters e do conceito de estado antes de abordar o papel das contas e dos programas como componentes fundamentais da Solana. Em seguida, examinamos como as transações permitem interações dinâmicas entre contas e programas.

Ao final deste artigo, você terá uma compreensão aprofundada do modelo de programação da Solana. Você conhecerá a arquitetura dos clusters, o papel crucial das contas no armazenamento de dados e o processo pelo qual as transações atualizam os dados das contas. Além disso, explorará recursos exclusivos da Solana, como seu sistema de aluguel e as transações versionadas.

O que são clusters da Solana?

No centro da arquitetura da Solana estão os clusters, um conjunto de validadores que trabalham em conjunto para processar transações e manter um único livro-razão. A Solana tem vários clusters distintos, cada um com uma finalidade específica:

  • Localhost: um cluster de desenvolvimento local disponível na porta padrão 8899. A Interface de Linha de Comando da Solana (CLI) inclui um validador de teste integrado, que pode ser personalizado conforme as necessidades de cada desenvolvedor sem exigir airdrops nem sofrer limites de taxa
  • Devnet: um ambiente sandbox sem consequências para testes e experimentos na Solana
  • Testnet: um ambiente no qual os principais colaboradores da Solana testam novas atualizações e recursos antes que cheguem à mainnet. Também é usado por desenvolvedores que desejam executar testes de desempenho
  • Mainnet Beta: o cluster ativo e sem permissão no qual ocorrem transações reais. Essa é a Solana “real”, onde usuários, desenvolvedores, detentores de tokens e validadores interagem diariamente

Cada cluster opera de forma independente, sem qualquer conhecimento dos demais. Transações enviadas ao cluster errado são rejeitadas para garantir a integridade de cada ambiente operacional.

Imagine os clusters como um heap monolítico de dados. Na ciência da computação, heap é uma região da memória na qual os dados podem ser armazenados e modificados dinamicamente. No entanto, é importante observar que os clusters não usam literalmente uma estrutura de dados heap. Essa analogia serve como ferramenta conceitual para ajudar a entender que os clusters consistem em várias regiões de memória que podem ser alocadas e desalocadas quando necessário. Entender os clusters como um heap dinâmico é essencial para compreender como os dados são gerenciados, acessados e protegidos na rede.

Você também pode pensar nesse heap monolítico de dados como uma espécie de armazém digital. Nele, os dados são como caixas em prateleiras, cada uma com rótulos exclusivos e regras específicas para movimentá-las e alterar seu conteúdo. Isso garante um sistema seguro e organizado, no qual somente movimentações ou alterações autorizadas são permitidas.

Os contratos inteligentes, conhecidos como programas na Solana, recebem sua própria parte do armazém, ou heap, que podem gerenciar. Embora um programa possa ler qualquer parte do espaço desse armazém, ele precisa de determinadas permissões para alterar o conteúdo de um espaço que não possui. A única ação permitida universalmente é transferir lamports, a criptomoeda nativa da Solana, para qualquer espaço do armazém.

Todo o estado reside nesse heap, inclusive os programas. Cada região tem um programa que a possui e gerencia. Os programas, por exemplo, pertencem ao BPFLoader, um programa responsável por carregar, implantar e atualizar programas on-chain. Chamamos essas regiões de memória, as caixas do nosso armazém digital, de contas.

O que são contas?

Tudo na Solana é uma conta. Pense nas contas como contêineres que armazenam dados de forma persistente, assim como arquivos em um computador. Elas são os componentes básicos do modelo de programação da Solana usados para armazenar estado (ou seja, o saldo da conta, informações de propriedade, se a conta contém um programa e informações de aluguel).

Há três tipos de contas na Solana:

  • Contas que armazenam dados
  • Contas que armazenam programas executáveis
  • Contas que armazenam programas nativos

Esses tipos de contas podem ser diferenciados ainda mais, conforme suas capacidades, em:

  • Contas executáveis - contas capazes de executar código
  • Contas não executáveis - contas usadas para armazenar dados sem a capacidade de executar código (porque não contêm código!)

Na imagem acima, temos alguns exemplos de contas executáveis e não executáveis. Entre as contas executáveis, o Bubblegum é um exemplo de Conta de Programa. Ele é um programa da Metaplex usado para criar e gerenciar NFTs compactados. O Programa de Votação é um exemplo de Conta de Programa Nativo. Ele é usado para criar e gerenciar contas que acompanham o estado de votação e as recompensas dos validadores. Abordaremos a diferença entre Contas de Programa e de Programa Nativo na seção O que são programas?. Por enquanto, é importante saber que há diferentes tipos de contas executáveis na Solana.

Além disso, toda conta não executável pode ser classificada como uma Conta de Dados. Alguns exemplos de Contas de Dados incluem:

Estrutura das contas

As contas são estruturadas de acordo com a struct AccountInfo:

Código
pub struct AccountInfo<'a> {
    pub key: &'a Pubkey,
    pub lamports: Rc>,
    pub data: Rc>,
    pub owner: &'a Pubkey,
    pub rent_epoch: Epoch,
    pub is_signer: bool,
    pub is_writable: bool,
    pub executable: bool,
}

As contas são identificadas por seu endereço (key), que é uma chave pública exclusiva de 32 bytes.

O campo lamports contém a quantidade de lamports pertencentes a essa conta. Um lamport equivale a um bilionésimo de um SOL, o token nativo da Solana.

data refere-se ao array de bytes de dados brutos armazenado por essa conta. Ele pode armazenar desde metadados de um ativo digital até saldos de tokens e pode ser modificado por programas.

O campo owner contém o proprietário dessa conta, representado pelo endereço de uma conta de programa. Há algumas regras sobre a propriedade das contas:

  • Somente o proprietário de uma conta pode alterar seus dados e sacar lamports
  • Qualquer pessoa pode depositar lamports em uma conta
  • O proprietário de uma conta pode transferir a propriedade para um novo proprietário, desde que os dados da conta sejam redefinidos como zero

O campo is_signer é um booleano que indica se uma transação foi assinada pelo proprietário da conta em questão. Em outras palavras, ele informa aos programas envolvidos na transação se a conta é signatária. Ser signatária significa que a conta possui a chave privada correspondente à chave pública e tem autoridade para aprovar a transação proposta.

O campo is_writable é um booleano que indica se os dados da conta podem ser modificados. A Solana permite que as transações especifiquem contas como somente leitura para viabilizar o processamento paralelo. Embora o runtime permita que contas somente leitura sejam acessadas simultaneamente por diferentes programas, ele trata possíveis conflitos de escrita em contas graváveis usando uma ordem de processamento de transações. Isso garante que somente transações sem conflitos sejam processadas em paralelo.

O campo executable é um booleano que indica se uma conta pode processar instruções. Sim, isso significa que os programas são armazenados em contas, e abordaremos esse tema na próxima seção. Antes, precisamos explicar o conceito de aluguel.

O campo rent_epoch indica a próxima época em que essa conta deverá pagar aluguel. Uma época é o número de slots durante os quais uma programação de líderes é válida. Diferentemente dos arquivos tradicionais em um sistema operacional, as contas na Solana têm uma vida útil expressa em uma quantidade de lamports. A ideia de que a existência contínua de uma conta depende de seu saldo em lamports nos leva ao conceito de aluguel.

Aluguel

O aluguel é um custo de armazenamento cobrado para manter as contas ativas na Solana e garantir que permaneçam na memória dos validadores. A cobrança do aluguel é calculada com base em épocas, uma unidade de tempo definida pelos slots durante os quais uma programação de líderes é válida. Veja como o aluguel funciona:

  • Cobrança de aluguel - o aluguel é cobrado uma vez por época. Ele também pode ser cobrado quando uma conta é referenciada por uma transação
  • Distribuição do aluguel - parte do aluguel cobrado é queimada, ou seja, removida permanentemente de circulação. O restante é distribuído às contas de votação após cada slot
  • Pagamento do aluguel - se uma conta não tiver lamports suficientes para pagar o aluguel, seus dados serão removidos e a conta será desalocada em um processo conhecido como coleta de lixo
  • Isenção de aluguel - as contas podem ficar isentas de aluguel se mantiverem um saldo mínimo equivalente a dois anos de pagamentos de aluguel. Todas as novas contas devem atingir esse limite de isenção, que depende do tamanho da conta
  • Recuperação do aluguel - os usuários podem fechar uma conta para recuperar os lamports restantes. Isso permite recuperar o aluguel armazenado em uma conta

O aluguel pode ser estimado usando o endpoint RPC getMinimumBalanceForRentExemption para um determinado tamanho de conta. O Test Drive simplifica esse processo ao aceitar o tamanho dos dados da conta em usize. O subcomando de aluguel da CLI da Solana também pode ser usado para estimar a quantidade mínima de SOL necessária para uma conta ficar isenta de aluguel. Por exemplo, no momento em que este artigo foi escrito, executar o comando solana rent 20000 retorna Mínimo para isenção de aluguel: 0.14009088 SOL.

Endereços na Solana

Na verdade, existem dois “tipos” de endereço na Solana. Para criar endereços, a Solana usa ed25519, um esquema de assinatura EdDSA que utiliza SHA-512 (SHA-2) e a curva elíptica Curve22519. Isso resulta em chaves públicas de 32 bytes, que funcionam como o formato de endereço principal. Elas podem ser usadas diretamente, pois não passam por hash.

Para que um endereço seja válido, ele deve ser um ponto na curva ed25519. No entanto, nem todos os endereços precisam ser derivados dessa curva. Os Endereços Derivados de Programa (PDAs) são gerados fora da curva, o que significa que não têm uma chave privada correspondente e não podem ser usados para assinar. Os PDAs são criados por meio do Programa de Sistema e usados quando programas precisam gerenciar contas. Este é apenas um adendo para que você saiba que existem diferentes tipos de endereço na Solana. Abordaremos os PDAs em um artigo futuro.

Como as contas da Solana diferem das contas da Ethereum?

A Ethereum tem dois tipos principais de conta: contas de propriedade externa (EOAs) e contas de contrato. As EOAs são controladas por chaves privadas, enquanto as contas de contrato são regidas pelo código de seus contratos e não podem iniciar transações por conta própria.

Tanto as EOAs quanto as contas de contrato seguem a mesma estrutura de conta:

  • Saldo - toda conta tem um saldo medido em Ether
  • Nonce - para EOAs, é a contagem de transações enviadas pela conta. Para contratos, é o número de contratos criados pela conta
  • Raiz de armazenamento - um hash de 256 bits do nó raiz de uma Merkle Patricia Trie, que representa uma codificação do conteúdo armazenado na conta
  • CodeHash - o hash do código da Ethereum Virtual Machine (EVM) do contrato. Ele é imutável, ou seja, seu código não muda após a criação, embora seu estado possa mudar. É importante observar que há exceções para a atualização de contratos na Ethereum, como o uso de padrões de proxy, mas isso está fora do escopo deste artigo. Para EOAs, esse é o hash de uma string vazia, pois EOAs não contêm código

A Solana adota um modelo de contas mais uniforme, no qual qualquer conta pode se tornar um programa. A separação entre código e dados promove um ambiente mais eficiente e flexível. Os programas da Solana não têm estado e interagem com várias contas de dados sem implantações redundantes. Isso é especialmente vantajoso para aplicações de finanças descentralizadas (DeFi), nas quais um usuário pode querer interagir com vários protocolos sem mover ativos entre programas diferentes. Em contrapartida, o modelo de programação da Ethereum combina código e estado em uma única entidade. Isso torna as interações mais complexas e potencialmente mais caras devido aos requisitos de gas para alterações de estado.

As contas da Solana costumavam pagar aluguel e precisavam manter um saldo mínimo para permanecer ativas. Isso garante que contas não utilizadas ou com fundos insuficientes sejam eventualmente recuperadas pela rede, reduzindo o inchaço do estado. Atualizações recentes eliminaram as contas que pagam aluguel na mainnet: agora, as contas precisam ser isentas de aluguel. Em comparação, a Ethereum usa gas para gerenciar a alocação de recursos. Nesse modelo, o armazenamento de contratos persiste indefinidamente, a menos que seja explicitamente apagado. A abordagem da Solana oferece uma estrutura de custos mais previsível para o armazenamento de estado, enquanto os custos da Ethereum podem variar e se tornar proibitivos durante períodos de congestionamento da rede.

Na seção seguinte, examinaremos como a Solana separa a lógica dos programas do estado. Em comparação com o modelo de programação da Ethereum, você verá como essa abordagem modular viabiliza operações on-chain mais eficientes e oferece aos desenvolvedores uma estrutura de custos transparente e previsível.

O que são programas da Solana?

Programas são contas executáveis pertencentes ao BPF Loader. Eles são executados pelo Runtime da Solana, projetado para processar transações e a lógica dos programas.

Uma das características marcantes do modelo de programação da Solana é a separação entre código e dados. Os programas não têm estado, ou seja, não armazenam nenhum estado internamente. Em vez disso, todos os dados com os quais precisam operar ficam armazenados em contas separadas, que são passadas aos programas por referência por meio de transações. Esse design permite que uma única implantação genérica de um programa interaja com diferentes contas.

Os programas na Solana podem:

  • Ter contas adicionais
  • Ler ou creditar outras contas
  • Modificar dados ou debitar as contas que possuem

Há dois tipos de programas:

  • Programas on-chain - são programas escritos por usuários e implantados na Solana. Eles podem ser atualizados por sua autoridade de atualização, normalmente a conta que implantou o programa
  • Programas nativos - são programas integrados ao núcleo da Solana. Eles fornecem as funcionalidades fundamentais necessárias para o funcionamento dos validadores. Programas nativos só podem ser atualizados por meio de atualizações de software em toda a rede. Exemplos comuns incluem o Programa de Sistema, o Programa BPF Loader e o Programa de Votação.

Tanto os programas on-chain quanto os nativos podem ser chamados por usuários e outros programas. A principal diferença está nos mecanismos de atualização: programas on-chain podem ser atualizados por sua autoridade de atualização, enquanto programas nativos só podem ser atualizados como parte das atualizações do cluster.

A Solana Labs mantém um grupo selecionado de programas on-chain conhecido como Biblioteca de Programas da Solana. Essa biblioteca viabiliza diversas operações on-chain, incluindo empréstimos de tokens e a criação de pools de stake. O Programa de Conta de Token Associada, por exemplo, define um padrão e um mecanismo para vincular a carteira de um usuário às respectivas contas de tokens. Além disso, a SPL é dinâmica. Programas como o Token-2022 se baseiam nas funcionalidades fornecidas pelo Programa de Tokens e as ampliam.

O desenvolvimento de programas na Solana geralmente é feito em Rust com a ajuda do Anchor, um framework opinativo que simplifica a criação de programas ao reduzir código repetitivo e agilizar a serialização e a desserialização. Embora Rust seja a linguagem preferida, os desenvolvedores não estão limitados a ela: é possível usar C, C++ e qualquer linguagem direcionada ao backend BPF do LLVM (ou seja, um componente do LLVM que permite compilar programas em bytecode BPF). Avanços recentes do Solang e da Neon Labs permitiram que os desenvolvedores usassem Solidity no desenvolvimento de programas.

Em geral, os programas são desenvolvidos e testados no Localhost e na Devnet antes de serem implantados na Testnet ou na Mainnet Beta. Os desenvolvedores podem implantar seus programas por meio da CLI da Solana com o comando solana program deploy <path to program>. Depois de compilado em um objeto compartilhado ELF contendo o bytecode BPF, o programa é enviado ao cluster designado da Solana. Os programas implantados ficam em contas marcadas como executable, e o endereço da conta funciona como program_id.

Inicialmente, os programas na Solana eram implantados em contas com o dobro do tamanho do programa. A atualização 1.16 da Solana adiciona suporte a contas redimensionáveis, oferecendo mais flexibilidade e melhores opções de alocação de recursos aos desenvolvedores. Agora, um desenvolvedor pode implantar seu programa em uma conta menor e ampliar seu tamanho posteriormente.

Como mencionado acima, os programas são considerados sem estado porque todos os dados com os quais interagem são armazenados em contas separadas passadas por referência. Todos os programas têm um único ponto de entrada no qual ocorre o processamento de instruções, que recebe um program_id, um array de contas e os dados da instrução como um array de bytes. Os programas são executados pelo Runtime da Solana quando invocados por uma transação.

O que são transações?

As transações são a base da atividade on-chain. Elas servem como mecanismo pelo qual os programas são invocados e as alterações de estado são realizadas. Uma transação na Solana é um conjunto de instruções que informa aos validadores quais ações devem executar, em quais contas e se têm as permissões necessárias para isso.

Uma transação consiste em três partes principais:

  • Um array de contas para leitura ou gravação
  • Uma ou mais instruções
  • Uma ou mais assinaturas

As transações na Solana seguem a struct Transaction. Ela fornece as informações necessárias para que a rede processe e valide as ações. Sua definição é a seguinte:

Código
pub struct Transaction {
    pub signatures: Vec,
    pub message: Message,
}

O campo signatures contém um conjunto de assinaturas correspondentes ao Message serializado. Cada assinatura está associada a uma chave de conta da lista account_keys do Message, começando pelo pagador da taxa. O pagador da taxa é a conta responsável por cobrir as taxas incorridas no processamento de uma transação. Normalmente, essa é a conta que inicia a transação. O número de assinaturas exigidas é igual a num_required_signatures, definido no MessageHeader da mensagem.

O próprio message é uma struct do tipo Message. Sua definição é:

Código
pub struct Message {
    pub header: MessageHeader,
    pub account_keys: Vec,
    pub recent_blockhash: Hash,
    pub instructions: Vec,
}

O header da mensagem contém três inteiros sem sinal de 8 bits: o número de assinaturas exigidas (ou seja, num_required_signatures), o número de signatários somente leitura e o número de não signatários somente leitura.

O campo account_keys lista todos os endereços de contas envolvidos na transação. As contas que solicitam acesso de leitura e gravação aparecem primeiro, seguidas pelas contas somente leitura.

recent_blockhash é um blockhash recente que contém um hash SHA-256 de 32 bytes. Ele é necessário para indicar quando um cliente observou o livro-razão pela última vez e funciona como um prazo de validade para transações recentes. Os validadores rejeitam transações com um blockhash antigo. Além disso, incluir um blockhash recente ajuda a evitar transações duplicadas, pois qualquer transação completamente idêntica a uma anterior é rejeitada. Se, por qualquer motivo, uma transação precisar ser assinada muito antes de ser enviada à rede, um nonce de transação durável poderá ser usado no lugar de um blockhash recente para garantir que a transação seja única.

O campo instructions contém uma ou mais structs CompiledInstruction, cada uma determinando uma ação específica a ser executada pelos validadores da rede.

Instruções

Uma instrução é uma diretiva para uma única invocação de um programa da Solana. Ela é a menor unidade da lógica de execução em um programa e funciona como a unidade operacional mais básica da Solana. Os programas interpretam os dados passados por uma instrução e operam nas contas especificadas. A struct Instruction é definida como:

Código
pub struct Instruction {
    pub program_id: Pubkey,
    pub accounts: Vec,
    pub data: Vec,
}

O campo program_id especifica a chave pública do programa que será executado. Esse é o endereço do programa que processará a instrução. O proprietário da conta do programa, indicado por essa chave pública, especifica o loader responsável por inicializar e executar o programa. Após a implantação, o loader marca como executáveis os programas on-chain no Solana Bytecode Format (SBF). O runtime da Solana rejeitará qualquer transação que tente invocar contas que não estejam marcadas como executáveis.

O campo accounts lista as contas que a instrução pode ler ou gravar. Essas contas devem ser fornecidas como valores AccountMeta. Toda conta cujos dados possam ser alterados pela instrução deve ser especificada como gravável; caso contrário, a transação falhará. Isso ocorre porque os programas não podem gravar em contas que não possuem ou para as quais não têm as permissões necessárias. O mesmo se aplica à alteração dos lamports de uma conta: subtrair lamports de uma conta que não pertence ao programa fará a transação falhar, enquanto adicionar lamports a qualquer conta é permitido. O campo accounts também pode especificar contas que não são lidas nem gravadas pelo programa. Isso é feito para afetar o agendamento da execução do programa pelo runtime, mas essas contas serão ignoradas nos demais aspectos.

data é um vetor de uso geral de inteiros sem sinal de 8 bits que serve como a entrada passada ao programa. Esse campo é crucial, pois contém as instruções codificadas que o programa executará.

A Solana é independente do formato dos dados das instruções. No entanto, oferece suporte integrado à serialização por meio de bincode e borsh (Binary Object Representation Serializer for Hashing). Serialização é o processo de converter estruturas de dados complexas em uma série simples de bytes que pode ser transmitida ou armazenada. A escolha da codificação dos dados deve considerar a sobrecarga da decodificação, pois tudo ocorre on-chain. A serialização Borsh costuma ser preferida em vez de bincode, porque tem uma especificação estável, uma implementação em JavaScript e geralmente é mais eficiente.

Os programas usam funções auxiliares para simplificar a construção das instruções compatíveis. Por exemplo, o Programa de Sistema oferece uma função auxiliar para construir a instrução SystemInstruction::Assign:

Código
pub fn assign(pubkey: &Pubkey, owner: &Pubkey) -> Instruction {
    let account_metas = vec![AccountMeta::new(*pubkey, true)];
    Instruction::new(
        system_program::id(),
        &SystemInstruction::Assign { owner: *owner },
        account_metas,
    )
}

Essa função constrói uma instrução que, quando processada, altera o proprietário da conta especificada para o novo proprietário fornecido.

Uma única transação pode conter várias instruções, executadas de forma sequencial e atômica na ordem em que aparecem. Isso significa que todas as instruções são concluídas com sucesso ou nenhuma delas é. Também significa que a ordem das instruções pode ser crucial. Os programas devem ser reforçados para processar com segurança qualquer sequência possível de instruções e evitar possíveis explorações.

Por exemplo, durante a desinicialização, um programa pode tentar desinicializar uma conta definindo seu saldo de lamports como zero. Isso pressupõe que o runtime da Solana excluirá a conta. Essa suposição é válida entre transações, mas não entre instruções ou Invocações Entre Programas (abordaremos Invocações Entre Programas em um artigo futuro). O programa deve zerar explicitamente os dados da conta para se proteger contra essa possível falha no processo de desinicialização. Caso contrário, um invasor poderia emitir uma instrução subsequente para explorar a suposta exclusão, por exemplo, reutilizando a conta antes da conclusão da transação.

O que são transações versionadas?

As transações na Solana usam os padrões de Unidade Máxima de Transmissão (MTU) do IPv6 para garantir a transmissão rápida e confiável de dados em um cluster. A stack de rede da Solana usa um tamanho de MTU conservador de 1.280 bytes. Depois de reservar espaço para os cabeçalhos, restam 1.232 bytes para os dados do pacote. Consequentemente, as transações da Solana ficam limitadas a esse tamanho.

Essa restrição de tamanho viabiliza várias melhorias de rede, mas também limita a complexidade das operações que podem ser executadas em uma única transação. Como cada endereço de conta ocupa 32 bytes de armazenamento, uma transação pode armazenar até 35 contas sem instruções. Essa restrição gera desafios para casos de uso que exigem mais de 35 contas sem assinatura em uma única transação.

Para resolver isso, foi introduzido um novo formato de transação com suporte a várias versões. Atualmente, o runtime da Solana oferece suporte a duas versões de transação:

  • legacy - o formato de transação original
  • 0 (Versão 0) - o formato de transação mais recente, que inclui suporte a Tabelas de Consulta de Endereços

A Versão 0 foi lançada para oferecer suporte a Tabelas de Consulta de Endereços (ALTs). Essencialmente, elas armazenam endereços de contas em uma estrutura de dados semelhante a uma tabela on-chain. Essas tabelas são contas separadas que armazenam endereços de contas e permitem referenciá-los em uma transação usando um índice u8 de 1 byte. Isso reduz significativamente o tamanho de uma transação, pois cada conta incluída precisa usar apenas 1 byte em vez de 32 bytes. As ALTs são especialmente úteis para operações complexas que envolvem muitas contas, como as comuns em aplicações DeFi.

Este diagrama foi adaptado da seção sobre Transações versionadas do Solana Cookbook

O termo “transações versionadas” refere-se à forma como a Solana oferece suporte aos formatos de transação legado e da Versão 0. Essa abordagem garante a composibilidade e, ao mesmo tempo, incorpora melhorias no runtime.

Estrutura de uma transação versionada

Um VersionedTransaction é definido como:

Código
pub struct VersionedTransaction {
    pub signatures: Vec,
    pub message: VersionedMessage,
}

O campo signatures é uma lista de assinaturas dos signatários da transação. Elas servem para autenticar e preservar a integridade da transação. O message é o conteúdo efetivo da transação. Ele é encapsulado pelo tipo VersionedMessage, um wrapper enum simples que trata tanto mensagens legadas quanto da Versão 0:

Código
pub enum VersionedMessage {
    Legacy(Message),
    V0(Message),
}

A versão da mensagem é determinada pelo primeiro bit no processo de serialização. Se o primeiro bit estiver definido, os 7 bits restantes serão usados para determinar qual versão de Message será serializada, começando pela Versão 0. Se o primeiro bit não estiver definido, todos os bytes serão usados para codificar o formato legado de Message. Isso ocorre porque existem duas structs Message com nomes idênticos, mas separadas em módulos diferentes: legacy e v0.

Um Message representa o formato interno condensado de uma transação. Ele é usado para transmissão pela rede e manipulação pelo runtime. Abrange uma lista linear de todas as contas usadas pelas instruções da transação, um MessageHeader que detalha a estrutura do array de contas, um blockhash recente e uma codificação compacta das instruções da mensagem. Esta é a estrutura da struct Message v0:

Código
pub struct Message {
    pub header: MessageHeader,
    pub account_keys: Vec,
    pub recent_blockhash: Hash,
    pub instructions: Vec,
    pub address_table_lookups: Vec,
}

A diferença entre uma mensagem legada e uma mensagem v0 é a inclusão do campo address_table_lookups.

Integração do modelo de programação ao fluxo de transações da Solana

O modelo de programação da Solana é profundamente integrado aos seus sistemas de contas e transações. Veja como esses conceitos se conectam:

  • Contas como estado - As contas na Solana funcionam como contêineres de estado para os programas. O modelo de programação gira em torno da modificação dos dados armazenados nesses contêineres em resposta a instruções
  • Instruções - Os programas definem a lógica para processar as instruções contidas em uma transação. Essas instruções são os componentes acionáveis que interagem com os dados das contas
  • Serialização e processamento - Quando uma transação é serializada, as instruções do programa determinam as alterações nos estados das contas. O processo de serialização respeita o design do programa, seja ele baseado no formato de transação legado ou da Versão 0
  • Atomicidade - O modelo de programação da Solana garante o processamento atômico das instruções. Os programas devem ser projetados para lidar com transações simultâneas de forma segura e eficiente
  • Escalabilidade - O modelo de programação da Solana oferece suporte à escalabilidade por meio de recursos como Tabelas de Consulta de Endereços (ALTs). Essas tabelas reduzem o tamanho de uma transação e aumentam o número de contas que ela pode referenciar

O modelo de programação da Solana não envolve apenas escrever código, mas também entender como esse código interage com o ecossistema mais amplo. As contas são essenciais para esse modelo e funcionam como o principal meio de armazenar e modificar dados na rede. As transações viabilizam a atividade on-chain ao informar aos validadores quais dados precisam ser criados, atualizados ou excluídos. Uma compreensão aprofundada desses aspectos é essencial para que os desenvolvedores criem aplicações otimizadas para desempenho e sinergia no ecossistema da Solana.

Conclusão

Parabéns! Neste artigo, percorremos as complexidades da arquitetura de sistema da Solana e exploramos o conceito de clusters como heaps monolíticos de dados. Descobrimos como esse heap é organizado em regiões de memória distintas, conhecidas como contas, que formam a base do modelo de programação da Solana. As contas armazenam tudo, desde os tokens dos usuários até os próprios programas que definem o comportamento da rede, e tudo isso é modificado por meio de transações.

Para desenvolvedores, entender a abordagem da Solana à computação descentralizada é crucial. Compreender os detalhes das contas, dos programas e das transações é necessário para criar aplicações que aproveitem plenamente os recursos da Solana. Trata-se de entender um sistema no qual o código é desacoplado do estado. Isso resulta em programas sem estado que interagem com dados por meio de contas em uma escala sem precedentes de composibilidade e capacidade de atualização.

Tanto para investidores quanto para usuários casuais, entender como o design da Solana cria um ecossistema robusto, flexível e eficiente é crucial para reconhecer a viabilidade da plataforma e sua capacidade de fomentar aplicações inovadoras que só são possíveis na Solana.

Se você chegou até aqui, anônimo, obrigado! Pronto para se aprofundar? Entre no nosso Discord e comece hoje mesmo a programar na Solana.

Recursos adicionais / Leituras complementares

Assine a Helius

Acompanhe as novidades mais recentes do desenvolvimento Solana e receba atualizações quando publicarmos

Imagem ampliada