1) Nos últimos 4-5 anos, experimentei várias arquiteturas de aplicações Solana, e achei que já estava mais do que na hora de eu escrever os resultados. Começando pelo menos complicado e aumentando progressivamente a complexidade. Então lá vai: Arquitetura de Aplicações Solana, um tópico.
2) Vamos começar pelo modo fácil. Provavelmente é assim que seu primeiro app Solana. Uma interface react simples estabelece uma conexão com um RPC. Não há necessidade de um servidor API. O RPC é seu servidor. Nos primeiros dias, esses estavam cheios de getAccountInfos, lógica de construção personalizada de textos, etc. Depois, quando o desempenho piorar, você adiciona camadas de cache e loteamento. Entra em cena getMultipleAccounts. Talvez você também adicione assinaturas do websocket + polling para atualizar a interface ao vivo. Essa arquitetura permite prototipagem extremamente rápida. Praticamente não existe DevOps. Custos de servidor insignificantes (apenas implantar no Vercel, etc). Mas tem algumas falhas sérias.
3) O primeiro problema que você encontra são consultas complexas. Nessa arquitetura, tudo o que você tem é o RPC Solana vanilla. Isso significa que você precisa tratar o Solana da forma como um RPC o expõe — como um banco de dados NoSQL com um problema de atitude. Consultas de pontos não são problema. Você pode até ser super criativo com PDAs para explorar os dados do seu programa como se fosse um banco de dados de grafos. Mas assim que precisar fazer seu primeiro GPA, você vai ter dor máxima. A interface não é nada ergonômica. Se você tiver algum tipo de dado com comprimento dinâmico, ele não pode ser usado de jeito nenhum. Dependendo do seu provedor de RPC, pode ser incrivelmente lento. Mesmo sem GPAs, essa abordagem tende a ser muito mais lenta do que um app web2 típico com renderização do lado do servidor e um banco de dados normal.
4) O segundo problema que você encontra é a portabilidade da lógica de construção de transações. Com essa configuração, toda a lógica para construir transações está (a) no seu código frontend ou (b) nas bibliotecas que seu código importa. No caso de (a), qualquer um que queira construir transações fora do seu frontend vai sofrer o máximo de dor (isso inclui você, quando inevitavelmente precisar de mais app). No caso de (b) qualquer alteração na lógica de construção de transações exige publicações de bibliotecas, todos atualizando seus pacotes e então atualizações da interface. Depender fortemente de ferramentas do Anchor, como a resolução de contas, pode minimizar a quantidade de lógica que precisa ser portada — mas o problema permanece. Isso rouba sua agilidade e dificulta a troca de endpoints de contratos inteligentes, garantindo que todas as versões da lógica do seu TX Building continuem funcionando.
5) O terceiro problema que você enfrenta é o fato de que as interfaces geralmente são ruins em enviar transações, especialmente com lógica de retentativa. Um usuário pode navegar para fora da página, TX para de tentar novamente. Grandes quantidades de transações tendem a ter dificuldade para ser alcançadas. É difícil depurar de longe por que as coisas não estão caindo.
6) O último problema aqui é que você não é o único com essa arquitetura. Um RPC é valioso, e você basicamente precisa expor a URL do RPC no seu frontend. Agora, você acaba em um jogo de gato e rato para garantir que ninguém esteja roubando seu RPC e aumentando seus custos.
7) E agora? Normalmente, mesmo que você não esteja abordando a portabilidade do transplante, acaba precisando responder às consultas da lista. gPA é ruim, e todos sabemos disso. Assim, você pode construir uma arquitetura híbrida. Nessa arquitetura, você mantém a capacidade de prototipar rapidamente, mas empurra as consultas difíceis e feias para uma API. Um bom exemplo concreto disso é a governança — você tem propostas sendo criadas com um conjunto de tags ("Econômica", "Técnica", etc). O gPA não pode filtrar por etiqueta.
8) Essa arquitetura não resolveu a portabilidade das transações, nem as pessoas tirando seu RPC. Mas em escala, pelo menos você pode resolver o problema dos GPAs lentos/impossíveis. Isso introduz um novo problema — os indexadores. Falaremos mais sobre isso depois.
9) Por fim, você tem o que eu chamaria de stack Solana "enterprise". Você não está mais tratando o Solana como um banco de dados NoSQL. Em vez disso, você está tratando como um ônibus de eventos. A interface não sabe nada sobre o modelo de dados da Solana. O servidor constrói as transações e as passa para a interface para assinatura, depois as envia para a própria Solana. Ele trata isso como um evento e espera que ele se propague de volta para os indexadores, o que alterará os dados subjacentes. Essa configuração tem ótima portabilidade de transações – qualquer um pode acessar sua API com parâmetros limpos e recuperar transações/instruções. Isso cria uma interface extremamente rápida — para a interface, isso é basicamente web2. Você pode aproveitar ao máximo o SSR. O RPC é abstraído — ninguém pode roubar seus créditos. Mas essa configuração tem seus problemas
10) O primeiro problema que você vai encontrar é dor no indexador. Embora isso tenha sido aliviado nos últimos anos (graças às equipes Triton, Helius e StreamingFast), ainda acabo batendo no nosso indexador com uma chave inglesa regularmente. Você vai perder mensagens. Quando você perde uma mensagem, sua interface fica estranha (exemplo: eu te enviei um NFT, na cadeia você recebeu, meu banco de dados diz que eu ainda possuo). Esse tipo de problema é irritante de depurar. A culpa é sua? É seu provedor de dados? Sabe-se lá! Lá se foi sua tarde.
11) O próximo problema que você vai enfrentar é o timing. Quando você usa diretamente o RPC para tudo, eles permitem que você cumpra compromissos e lide com os dados mais recentes. Com um indexador, tudo isso é manual. Isso significa que, ao construir transações, pode estar construindo-as com base em dados desatualizados. Você devolve uma transação fadada ao fracasso. Você pode resolver o problema dos dados desatualizados usando provedores de dados que fornecem dados extremamente rápidos (por exemplo, fluxo de laser Helius). Mas aí você precisa lidar manualmente com as reorganizações. Ou seja, os dados que você indexa precisam ser desindexados se esse texto não foi realmente aprovado. Isso é um pesadelo.
12) Você pode "contornar" problemas de tempo construindo apenas transações usando dados do RPC, e usando seus dados indexados apenas para alimentar a interface. Mas, aí, os usuários ainda terão problemas com possíveis inconsistências entre a interface e a cadeia. Por exemplo, o frontend diz que eu possuo esse NFT e posso transferi-lo, então o backend grita comigo dizendo que não posso.
13) O último problema que você encontra nessa configuração é o custo, e se formos melodramáticos, "a morte da descentralização." O sonho do web3 era não ter que implantar muitos servidores centralizados. Agora você implantou infraestrutura suficiente para conseguir um cargo de arquiteto principal em uma empresa web2. Custa dinheiro. Custa tempo. E tudo é muito centralizado. Quão descentralizado é seu protocolo se a melhor forma de interagir com ele é via uma API web2? E tem uns 72 desenvolvedores no Solana que saberiam como interagir com ele sem essa API.
14) No fim das contas, não vou morrer em nenhuma disputa em torno da descentralização. O que é melhor para os usuários tende a ser a melhor escolha. A configuração "empresarial" leva a webapps rápidos e modernos e a uma separação clara de preocupações. Por outro lado, isso aumenta o custo de DevOps e te deixa menos ágil. Recomendo que a maioria das startups comece com o método direto para RPC, a menos que você esteja construindo algo que precise ser rápido ou tenha semântica complexa de consultas. O tempo de lançamento é fundamental. Você sempre pode contratar um engenheiro de nível médio depois e colocá-lo na masmorra de indexação.
15) Fin. Se alguém aqui encontrou uma configuração melhor, me avise. Essas são todas as coisas que já tentei. Tenho gostado bastante de mexer na configuração corporativa ultimamente.
40,08K