NOVO: Helius adquire a Light Protocol
Uma lâmpada e uma placa de circuito
Blog/Fundamentos

Como transformar sua ideia em um programa Solana (contrato inteligente)

Educação para desenvolvedoresMike MacCana no XMike MacCana no LinkedIn
7 min de leitura

Vamos projetar um programa Solana. O ecossistema Solana oferece inúmeros artigos sobre como entender o modelo de programação da Solana e criar pequenos programas de demonstração, que são uma excelente forma de iniciantes aprenderem sobre Solana e Anchor. No entanto, programas reais envolvem questões mais complexas. 

Neste artigo, analisaremos um programa real que queremos criar e abordaremos: 

  1. Definir nossos dados como contas Solana
  2. Criar relações entre nossos dados
  3. Armazenar tokens em nosso programa
  4. Usar índices para acelerar nossas leituras
  5. Usar sharding para acelerar gravações

O objetivo deste exemplo é ajudar você a pegar suas próprias ideias e entender como modelá-las como programas e contas Solana. 

Observação: este artigo pressupõe que você conheça os fundamentos do Anchor. 

Exemplo de programa Solana — Criando um mercado de previsões

O programa que projetaremos hoje é um mercado de previsões semelhante ao Polymarket, Hedgehog ou Drift BET. Caso você não conheça os mercados de previsões, eles permitem que as pessoas apostem em diferentes resultados de um evento. Pode ser qual time vencerá o Super Bowl, quem ganhará o Oscar de “Melhor Diretor”, se o governo fará um anúncio até determinado momento ou qualquer outro evento do mundo real com um resultado específico. Se as pessoas apostarem no resultado vencedor, elas receberão prêmios do bolão de apostas.

Arquitetura do mercado de previsões

Esta é a arquitetura principal de um mercado de previsões e como cada elemento se relaciona com os demais:

  • Há vários eventos.
  • Cada evento tem vários resultados. No fim, um desses resultados será definido como o vencedor.
  • Os usuários fazem várias apostas em cada resultado. Quando um usuário faz uma aposta, seus fundos são adicionados ao bolão de prêmios desse evento.

Quando o evento é “resolvido” (ou seja, quando sabemos qual é o resultado vencedor):

  • Os usuários que apostaram no resultado vencedor poderão resgatar seus prêmios
  • Os vencedores receberão uma parte do bolão de prêmios (menos a comissão da casa)
  • A parte de cada vencedor no bolão de prêmios será baseada na proporção de suas apostas sobre o resultado vencedor.

1. Projetando nosso aplicativo como contas Solana

Se estivéssemos projetando este programa para usar um banco de dados relacional, pensaríamos em:

  • Itens de dados semelhantes armazenados como linhas em uma tabela 
  • Chaves primárias usadas para identificar cada dado de forma única
  • As colunas da tabela definem os atributos esperados de cada item de dados e seus tipos

Na Solana, esses conceitos correspondem aproximadamente a:

  • Itens de dados semelhantes são armazenados usando o mesmo tipo de conta 
  • Endereços são usados para identificar cada dado de forma única
  • A struct (chaves e tipos de dados) define os atributos de cada item

Veja os mesmos dados representados tanto em uma tabela tradicional de banco de dados quanto em contas Solana:

2. Mapeando relações entre dados

As relações entre itens de dados funcionam de forma muito diferente na Solana. Bancos de dados tradicionais usam relações (ou seja, a conexão lógica entre tabelas). A Solana trata relações de um para muitos como um vetor de endereços, no qual cada endereço contém uma conta com o item. 

Por exemplo, eventos têm “resultados” que formam um vetor de endereços de resultados. O Anchor representa isso como Vec<Pubkey>, embora endereços PDA (como o nosso resultado) não sejam realmente chaves públicas.

3. Armazenando tokens

Diferentemente dos bancos de dados tradicionais, programas Solana também podem armazenar fundos — e não apenas valores de saldo — em uma conta.

Em nosso exemplo, o evento precisa de uma conta de tokens para seu bolão de prêmios. A PDA do evento será proprietária da conta do bolão de prêmios. Quando os usuários fazem apostas, eles enviam tokens para essa conta. Mais importante ainda: quando resgatam suas apostas, nosso programa assina a transação como a conta do evento para retirar tokens do bolão de prêmios.

4. Reduzindo o esforço de leitura

Nosso programa precisa oferecer a resposta mais rápida possível aos usuários e, como desenvolvedores, queremos evitar pagar desnecessariamente por leituras de contas dispensáveis. Podemos tornar nosso programa mais responsivo e eficiente usando totais acumulados e índices.

Calcular totais acumulados

Quando os usuários resgatarem seus prêmios, precisaremos saber exatamente quanto foi apostado em cada resultado. Mercados de previsões determinam o pagamento de um usuário vencedor com base na fórmula bolão de prêmios × valor da aposta ÷ total apostado no resultado vencedor.

No momento, armazenamos apenas o valor de cada aposta na conta da própria aposta. Para obter o total apostado em determinado resultado, precisaríamos ler todas as contas de apostas e somar os valores.

Em vez disso, vamos adicionar um campo a cada resultado — total_amount — e incrementá-lo quando os usuários fizerem apostas. Assim, quando os usuários vencerem, poderemos determinar facilmente o valor do pagamento sem precisar ler todas as apostas nesse resultado.

Usar índices

Também precisaremos encontrar todas as apostas de uma conta de usuário específica. Poderíamos buscar todas as contas de apostas usando getProgramAccounts() e filtrar aquelas cujo apostador corresponda ao endereço desse usuário. Embora o getProgramAccounts() rápido da Helius torne isso muito mais rápido do que em outros provedores de RPC, índices são uma alternativa comum. 

Portanto, vamos criar um índice para armazenar as apostas de cada usuário. Quando um usuário fizer uma nova aposta, criaremos esse item caso ele não exista e adicionaremos a aposta à lista de apostas desse usuário:

Também adicionaremos tags a cada evento para encontrar facilmente todos os eventos com as tags “esportes”, “política”, “europa”, “eua”, “política” etc. Criaremos outro índice para isso:

Agora podemos recuperar facilmente todos os eventos relevantes consultando a conta da tag do evento.

5. Reduzindo a contenção de gravação

Lembra que cada evento tem uma única conta de tokens que armazena as apostas desse evento? Sempre que um usuário adicionar uma nova aposta, tokens serão transferidos para essa conta. Em outras palavras, haverá uma gravação na conta.

A Solana é rápida porque paraleliza operações. No entanto, a atualização do saldo de uma única conta não pode ocorrer em paralelo. Ela precisa ser feita sequencialmente, pois cada conta deve ter um único saldo em qualquer momento. 

Se um novo evento for anunciado e receber muitas apostas, várias gravações ocorrerão simultaneamente na conta de tokens do evento, e as transações do nosso programa poderão parecer lentas. Isso é chamado de contenção de gravação: várias transações competem pelo acesso à conta.

Uma forma de permitir o paralelismo nesses casos é usar sharding. Um recurso é dividido em várias partes — chamadas shards — que podem ser acessadas em paralelo.

Como funciona o sharding

Os pagamentos recebidos são enviados para shards win_pool separadas de acordo com o valor do byte final da chave pública do apostador, usando a macro shard_num(). Isso garante que os pagamentos recebidos sejam rápidos.

Posteriormente, um handler de instrução do administrador pode consolidá-las em uma única conta de bolão de prêmios, garantindo liquidez na mesma conta para pagar os vencedores.

Também precisamos considerar a contenção de gravação caso um evento popular seja finalizado e todos os vencedores resgatem seus prêmios ao mesmo tempo. Também precisaremos retirar os fundos do bolão de prêmios o mais rápido possível.

A melhor opção aqui é evitar um processo de resgate. Se enviarmos os fundos sequencialmente assim que o evento for finalizado, os usuários não precisarão lidar com resgates lentos — seus prêmios já estarão depositados em suas contas.

No entanto, você precisa realmente ter usuários antes de se preocupar com multidões apostando ou resgatando seus prêmios. Se estiver planejando seu programa Solana e ainda não o tiver lançado, não será necessário fazer otimizações para lidar com um grande volume de tráfego de usuários que você ainda não tem. Caso não precise delas para o lançamento, considere a complexidade adicional de otimizações maiores como essa, sabendo que talvez precise implementá-las quando seu programa se tornar mais popular.

Conclusão

Neste artigo, exploramos em detalhes a criação de uma aplicação real na Solana. Agora você tem conhecimentos práticos para definir contas Solana, estabelecer relações entre dados, armazenar tokens e otimizar o desempenho usando índices e sharding. 

Se tiver outras dúvidas, fale com a @helius no X ou entre no Discord da Helius. Ampliaremos este exemplo de mercado de previsões no futuro, então acompanhe essas contas para receber novidades.

Com essas novas habilidades, chegou a hora de transformar suas ideias em programas Solana e dar vida a elas no ecossistema Solana. Bom código! Agradecemos a Ichigo pela revisão deste artigo e a r0bre por indicar a técnica de sharding de contas utilizada.

Recursos adicionais

Assine a Helius

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

Imagem ampliada