Você provavelmente já ouviu falar que o Telegram vai lançar a plataforma blockchain Ton . Mas você poderia ter perdido a notícia de que, há pouco tempo, o Telegram anunciou uma competição pela implementação de um ou mais contratos inteligentes para esta plataforma.
A equipe da Serokell, com vasta experiência no desenvolvimento de grandes projetos de blockchain, não pôde ficar de fora. Delegamos cinco funcionários para o concurso e, duas semanas depois, eles ocuparam o primeiro lugar com o apelido aleatório modesto Sexy Chameleon. Neste artigo, vou falar sobre como eles conseguiram. Esperamos que, nos próximos dez minutos, você leia pelo menos uma história interessante e, no máximo, encontre algo útil que possa aplicar em seu trabalho.
Mas vamos começar com um pequeno mergulho no contexto.
Concorrência e suas condições
Portanto, as principais tarefas dos participantes foram a implementação de um ou mais dos contratos inteligentes propostos, além de apresentar propostas para melhorar o ecossistema de TON. A competição foi realizada de 24 de setembro a 15 de outubro, e os resultados foram anunciados apenas em 15 de novembro. Por um longo tempo, dado que, durante esse período, o Telegram conseguiu conduzir e anunciar os resultados de concursos de design e desenvolvimento de aplicativos em C ++ para testar e avaliar a qualidade das chamadas VoIP no Telegram.
Selecionamos dois contratos inteligentes da lista proposta pelos organizadores. Para um deles, usamos ferramentas distribuídas com o TON e o segundo implementamos em um novo idioma desenvolvido por nossos engenheiros especificamente para o TON e incorporado ao Haskell.
A escolha de uma linguagem de programação funcional não é acidental. Em nosso blog corporativo, geralmente falamos sobre por que consideramos a complexidade das linguagens funcionais um grande exagero e por que geralmente preferimos que elas sejam orientadas a objetos. A propósito, ele também contém o original deste artigo .
Por que decidimos participar
Em resumo, porque nossa especialização são projetos não padronizados e complexos que requerem habilidades especiais e geralmente têm valor científico para a comunidade de TI. Apoiamos calorosamente o desenvolvimento de código aberto e estamos envolvidos em sua popularização, bem como cooperamos com as principais universidades da Rússia no campo da ciência da computação e matemática.
As tarefas interessantes do concurso e o envolvimento no projeto Telegram, que tanto amamos, eram em si uma excelente motivação, mas o fundo do prêmio tornou-se um incentivo adicional. :)
Pesquisa TON Blockchain
Monitoramos de perto novos desenvolvimentos no blockchain, inteligência artificial e aprendizado de máquina e tentamos não perder um único release significativo em cada uma das áreas em que trabalhamos. Portanto, quando a competição começou, nossa equipe já estava familiarizada com as idéias do white paper da TON . No entanto, antes de iniciar o trabalho com a TON, não analisamos a documentação técnica e o código fonte real da plataforma, portanto, o primeiro passo foi bastante óbvio - um estudo completo da documentação oficial no site e no repositório do projeto .
No início do concurso, o código já havia sido publicado; portanto, para economizar tempo, decidimos procurar um guia ou aperto escrito pelos usuários . Infelizmente, isso não deu resultado - além das instruções para a construção da plataforma no Ubuntu, não encontramos outros materiais.
A documentação em si foi completamente desenvolvida, mas foi difícil lê-la em alguns momentos. Muitas vezes, tivemos que voltar a certos pontos e passar de descrições de alto nível de idéias abstratas para detalhes de implementação de baixo nível.
Seria mais fácil se a especificação não tivesse uma descrição detalhada da implementação. As informações sobre como a máquina virtual apresenta sua pilha são mais perturbadoras para os desenvolvedores que criam contratos inteligentes para a plataforma TON do que para ajudá-los.
Nix: construindo um projeto
Na Serokell, somos grandes fãs do Nix . Coletamos nossos projetos para eles e os implantamos usando o NixOps , e o NixOS é instalado em todos os nossos servidores. Graças a isso, todas as nossas compilações são reproduzíveis e funcionam em qualquer sistema operacional no qual o Nix possa ser instalado.
Então começamos criando sobreposição Nix com uma expressão para criar TON . Usá-lo para compilar TON é o mais simples possível:
$ cd ~/.config/nixpkgs/overlays && git clone https://github.com/serokell/ton.nix $ cd /path/to/ton/repo && nix-shell [nix-shell]$ cmakeConfigurePhase && make
Observe que você não precisa instalar nenhuma dependência. O Nix magicamente fará tudo por você, se você usa o NixOS, Ubuntu ou macOS.
Programação para TON
O código do contrato inteligente da TON Network é executado na TON Virtual Machine (TVM). O TVM é mais complicado que a maioria das outras máquinas virtuais e possui uma funcionalidade muito interessante, por exemplo, pode trabalhar com continuações e links para dados .
Além disso, os caras da TON criaram três novas linguagens de programação:
Fift é uma linguagem de programação de pilha universal que lembra o Forth . Sua super habilidade é a capacidade de interagir com o TVM.
FunC é uma linguagem de programação de contrato inteligente, semelhante a C e compilada em outra linguagem - Fift Assembler.
Fift Assembler - Biblioteca Fift para gerar código executável binário para TVM. O Fift Assembler não possui um compilador. É uma linguagem específica de domínio incorporada (eDSL) .
Nossos trabalhos competitivos
Finalmente, é hora de analisar os resultados de nossos esforços.
Canal de pagamento assíncrono
Canal de pagamento - um contrato inteligente que permite que dois usuários enviem pagamentos para fora do blockchain. Como resultado, não apenas dinheiro é economizado (não há comissão), mas também tempo (você não precisa esperar até que o próximo bloco seja processado). Os pagamentos podem ser arbitrariamente pequenos e ocorrem quantas vezes forem necessárias. Ao mesmo tempo, as partes não precisam confiar umas nas outras, uma vez que a justiça da liquidação final é garantida por um contrato inteligente.
Encontramos uma solução bastante simples para o problema. Duas partes podem trocar mensagens assinadas, cada uma contendo dois números - o valor total pago por cada um dos participantes. Esses dois números funcionam como relógios de vetor em sistemas distribuídos tradicionais e definem a ordem "aconteceu antes" nas transações. Usando esses dados, o contrato poderá resolver qualquer conflito possível.
De fato, para implementar essa idéia, basta um número, mas deixamos os dois, pois conseguimos criar uma interface de usuário mais conveniente. Além disso, decidimos incluir um valor de pagamento em cada mensagem. Sem ela, se a mensagem for perdida por algum motivo, embora todos os valores e o cálculo final estejam corretos, o usuário poderá não perceber a perda.
Para testar nossa idéia, procuramos exemplos de como usar um protocolo de canal de pagamento simples e conciso. Surpreendentemente, encontramos apenas dois:
- Descrição de uma abordagem semelhante, apenas para o caso de um canal unidirecional.
- Um tutorial que descreve a mesma idéia que a nossa, mas sem explicar muitos detalhes importantes, como correção geral e o procedimento para resolver conflitos.
Tornou-se claro que faz sentido descrever nosso protocolo em detalhes, prestando atenção especial à sua correção. Após várias iterações, a especificação estava pronta e agora você também pode vê -la .
Implementamos um contrato para o FunC e criamos o utilitário de linha de comando para interagir com nosso contrato no Fift, conforme recomendado pelos organizadores. Poderíamos escolher qualquer outro idioma para nossa CLI, mas foi interessante experimentar o Fift para ver como ele se mostra em ação.
Honestamente, tendo trabalhado com o Fift, não vimos boas razões para preferir esse idioma a idiomas populares e usados ativamente com ferramentas e bibliotecas desenvolvidas. Programar na linguagem da pilha é bastante desagradável, porque você precisa ter sempre em mente o que está na pilha, e o compilador não ajuda.
Portanto, a única justificativa para a existência do Fift é, em nossa opinião, o seu papel como idioma de host do Fift Assembler. Mas não seria melhor incorporar o montador do TVM em um idioma existente e não criar um novo para isso, essencialmente o único objetivo?
TVM Haskell eDSL
Agora é hora de falar sobre o nosso segundo contrato inteligente. Decidimos desenvolver uma carteira com várias assinaturas, mas escrever outro contrato inteligente no FunC seria muito chato. Queríamos adicionar um pouco de entusiasmo, e ele se tornou nossa própria linguagem de montagem para o TVM.
Como o Fift Assembler, nossa nova linguagem é incorporável, mas em vez do Fift, escolhemos Haskell como host, o que nos permitiu usar totalmente seu sistema de tipos avançados. Ao trabalhar com contratos inteligentes, onde o preço de um pequeno erro pode ser muito alto, a digitação estática, em nossa opinião, é uma grande vantagem.
Para demonstrar como é o montador do TVM embutido no Haskell, implementamos uma carteira padrão nele. Aqui estão algumas coisas a serem observadas:
- Este contrato consiste em uma função, mas você pode usar o quanto quiser. Quando você define uma nova função no idioma do host (ou seja, em Haskell), nosso eDSL permite que você escolha se deseja que ele se transforme em um subprograma separado no TVM ou apenas seja incorporado ao local da chamada.
- Como Haskell, funções têm tipos que são verificados em tempo de compilação. Em nosso eDSL, o tipo de entrada da função é o tipo de pilha que a função espera, e o tipo de resultado é o tipo de pilha que será obtida após a chamada.
- O código possui anotações de tipo de pilha que descrevem o tipo esperado de pilha no ponto de discagem. No contrato original da carteira, esses eram apenas comentários, mas em nosso eDSL eles fazem parte do código e são verificados em tempo de compilação. Eles podem servir como documentação ou instruções que ajudam o desenvolvedor a encontrar o problema se o tipo de pilha for alterado conforme o código for alterado. Obviamente, essas anotações não afetam o desempenho do tempo de execução, pois nenhum código TVM é gerado para elas.
- Este ainda é um protótipo escrito em duas semanas, ainda resta muito trabalho a ser feito no projeto. Por exemplo, todas as instâncias de classe que você vê no código abaixo devem ser geradas automaticamente.
Veja como é a implementação da carteira multisig em nosso eDSL:
main :: IO () main = putText $ pretty $ declProgram procedures methods where procedures = [ ("recv_external", decl recvExternal) , ("recv_internal", decl recvInternal) ] methods = [ ("seqno", declMethod getSeqno) ] data Storage = Storage { sCnt :: Word32 , sPubKey :: PublicKey } instance DecodeSlice Storage where type DecodeSliceFields Storage = [PublicKey, Word32] decodeFromSliceImpl = do decodeFromSliceImpl @Word32 decodeFromSliceImpl @PublicKey instance EncodeBuilder Storage where encodeToBuilder = do encodeToBuilder @Word32 encodeToBuilder @PublicKey data WalletError = SeqNoMismatch | SignatureMismatch deriving (Eq, Ord, Show, Generic) instance Exception WalletError instance Enum WalletError where toEnum 33 = SeqNoMismatch toEnum 34 = SignatureMismatch toEnum _ = error "Uknown MultiSigError id" fromEnum SeqNoMismatch = 33 fromEnum SignatureMismatch = 34 recvInternal :: '[Slice] :-> '[] recvInternal = drop recvExternal :: '[Slice] :-> '[] recvExternal = do decodeFromSlice @Signature dup preloadFromSlice @Word32 stacktype @[Word32, Slice, Signature]
O código fonte completo do nosso eDSL e o contrato de carteira com várias assinaturas podem ser encontrados neste repositório. E, com mais detalhes, nosso colega George Agapov falou sobre os idiomas internos.
Conclusões sobre a competição e TON
No total, nosso trabalho levou 380 horas (juntamente com o conhecimento da documentação, reuniões e desenvolvimento). Cinco desenvolvedores participaram da competição: STO, líder da equipe, especialistas em plataformas blockchain e desenvolvedores de software Haskell.
Encontramos os recursos para participar do concurso sem dificuldade, pois o espírito do hackathon, o trabalho em equipe próximo, a necessidade de imersão rápida em aspectos das novas tecnologias são sempre emocionantes. Algumas noites sem dormir, a fim de alcançar resultados máximos em condições de recursos limitados, são compensadas por uma experiência inestimável e excelentes memórias. Além disso, o trabalho nessas tarefas é sempre um bom teste para os processos da empresa, pois é extremamente difícil obter resultados verdadeiramente decentes sem interação interna excelente.
Além da letra: ficamos impressionados com a quantidade de trabalho realizado pela equipe TON. Eles conseguiram construir um sistema de trabalho complexo, bonito e o mais importante. A TON provou ser uma plataforma com grande potencial. No entanto, para que esse ecossistema se desenvolva, muito mais precisa ser feito, tanto em termos de seu uso em projetos de blockchain quanto em termos de melhoria das ferramentas de desenvolvimento. Estamos orgulhosos de fazer parte desse processo agora.
Se, depois de ler este artigo, você ainda tiver dúvidas ou idéias sobre como aplicar o TON para resolver seus problemas, escreva-nos - teremos o prazer de compartilhar nossa experiência.