WEB3DEV

Cover image for Migrando do Solidity para o Cairo
Paulo Gio
Paulo Gio

Posted on

Migrando do Solidity para o Cairo

Orientando os Desenvolvedores na Expansão para a Programação em Cairo

Resumo

  • Desenvolvedores estão expandindo suas habilidades para incluir o Cairo, impulsionados pelo crescente destaque da Starknet.
  • O Solidity permite contratos inteligentes interoperáveis em nível global, mas exige repetição extensiva de cálculos computacionais.
  • A eficiência do Cairo deriva de sua capacidade de criar provas de execução de transações verificáveis usando uma única máquina.
  • Cairo e Solidity são linguagens de contrato inteligente, mas suas funcionalidades e princípios são distintos.

Introdução

Com o crescimento da Starknet (e a contínua empolgação em torno dos rollups), o Cairo se tornou uma das habilidades mais requisitadas na web3.

O Cairo — que é usado para escrever contratos inteligentes na Starknet e StarkEx, bem como em aplicações de escalonamento, como dYdX e ImmutableX — viu o número de seus desenvolvedores trabalhando em tempo integral aumentar em impressionantes 875% nos últimos dois anos e 83% ano após ano. E como o Cairo pode ser usado fora de blockchains sempre que qualquer prova de cálculo computacional é necessária, a adoção do Cairo por desenvolvedores deve apenas aumentar.

Muitos desses novos desenvolvedores que usam o Cairo estão migrando do Solidity — a linguagem de contrato inteligente na camada 1. Se você é um dos desenvolvedores fazendo essa mudança, estamos aqui para ajudar!

Neste artigo, vamos fornecer um guia para desenvolvedores que estão fazendo a transição de Solidity para Cairo. Vamos falar sobre o que torna o Cairo diferente, como o Cairo funciona de um ponto de vista técnico e, em seguida, analisar alguns exemplos de código para mostrar as principais diferenças entre as linguagens.

Vamos começar!

O que é o Cairo?

Cairo é a linguagem nativa para contratos inteligentes na Starknet, inspirada em Rust.

De acordo com a documentação do Cairo, “Cairo é a primeira linguagem Turing-completa para criar programas comprováveis por provas STARK (STARK-provable) para a computação geral.” Vamos dividir essa definição em partes.

Turing-completa significa que esta linguagem de programação pode simular uma máquina Turing-completa. Uma máquina Turing-completa (nomeada em homenagem a Alan Turing) é um computador que pode realizar qualquer cálculo computacional e executar qualquer algoritmo, desde que tenha tempo e recursos suficientes.

Comprovável por prova STARK significa que os programas escritos em Cairo podem ser executados de forma que uma prova STARK da execução pode ser criada eficientemente. Quando um programa escrito em Cairo é executado em qualquer máquina, é criada uma nova prova STARK (Scalable Transparent ARguments of Knowledge, ou Argumentos de Conhecimento Transparentes e Escaláveis) que permite a qualquer verificador independente verificar de forma sucinta a execução honesta do programa — sem ter que confiar na máquina em que os cálculos do programa foram realizados.

O Cairo 1.0 foi lançado nesta primavera (substituindo o Cairo 0) e já está disponível na Mainnet (rede principal) da Starknet.

Qual é o Melhor — Cairo ou Solidity?

Nenhum! De certa forma, é uma comparação de "maçãs com laranjas".

Solidity é a linguagem inicialmente usada para a adoção ampla da computação componível — um paradigma de programação no qual diferentes componentes do sistema podem ser usados sincronizadamente e compostos em um software complicado usando diferentes componentes como blocos de Lego.

O Solidity possibilitou que os contratos inteligentes fossem intrincadamente entrelaçados devido ao seguinte:

  • Bytecode que foi tornado público e transparente para o mundo
  • Estruturas ABI padrão (que permitiram a outros interagir com contratos inteligentes externos)
  • Uso da rede Ethereum para ter quase 100% de disponibilidade (ou uptime)
  • Uso da rede Ethereum como meio de execução de transações financeiras
  • Interoperabilidade global de contratos inteligentes devido a uma única EVM comum (uma cópia da qual é mantida por todos os validadores na rede)

Mesmo que o Solidity tenha alcançado uma miríade de primeiros lugares por ser a linguagem de contrato inteligente mais amplamente adotada, o Cairo tem uma única propriedade avassaladora: sua capacidade de criar programas comprováveis para a computação geral.

Essa única propriedade diferenciadora nos permite migrar de um sistema onde cada cálculo computacional tem que ser repetido centenas de milhares de vezes (esse é o número de validadores na rede Ethereum) para um sistema mais novo, onde apenas uma única máquina (chamada provadora) cria uma prova de execução correta de uma transação que os outros na rede podem verificar.

Diferenças entre a Máquina Virtual Cairo e a Máquina Virtual Ethereum

Para que a execução dos programas Cairo seja eficientemente convertida em uma prova STARK, existem algumas diferenças-chave entre a máquina virtual Cairo e a EVM (Ethereum Virtual Machine):

  1. Modelo de Memória: A Máquina Virtual Cairo usa um modelo de memória de gravação única. Um slot de memória não pode ser sobrescrito (diferente da EVM). Embora isso possa parecer uma sobrecarga altamente complexa, o compilador Cairo resolve esse problema, e a versão abstrata permite que variáveis mutáveis sejam usadas no código (mais sobre isso mais tarde). O modelo de memória de gravação única torna o Cairo um sistema mais previsível e verificável. Cada endereço de memória é escrito apenas uma vez, e ele retém seu valor até a execução do programa ser concluída. Isso significa que há um registro claro e inalterado do cálculo computacional, que é vital ao gerar provas STARK, pois elas dependem da verificação da exatidão dos cálculos.
  2. Corpos: Quando falamos de provas criptográficas, quase sempre falamos dessas provas sendo criadas para operações em elementos de um determinado corpo. Como discutido em nosso artigo sobre aritmetização, em matemática, um corpo é um conjunto de elementos com duas operações binárias, adição e multiplicação. Satisfaz certos axiomas, como fechamento, associatividade, comutatividade e a existência de inversos e elementos de identidade. Exemplos de corpos incluem números reais, números racionais e números complexos. Os elementos de tal corpo são os sujeitos de operações que fazem parte de qualquer cálculo computacional geral comprovável. Ao discutir corpos, é importante notar que alguns corpos são finitos (o corpo usado no Cairo também é finito). Em um corpo finito, o número de elementos é finito, e todos os elementos são menores que a maior "ordem" do corpo. A "ordem" de um corpo é igual ao maior número que os elementos de um corpo podem atingir mais um. Além disso, todas as operações de adição e multiplicação resultam em um número, o módulo da maior ordem. Então, por exemplo, em um corpo de ordem 6, a adição 3+4 resultaria em (3+4) mod 6 = 7 mod 6 = 1. O Cairo usa um corpo finito de ordem 2251 + 17 * 2192 + 1. Como, ao gerar provas, todos os elementos precisam ser elementos do corpo, a Máquina Virtual Cairo usa elementos do corpo como base para todas as operações. Ela não segue o sistema convencional de uint256 ou uint32 como a EVM faz. No entanto, técnicas de abstração podem ser criadas para usar o tipo uint256 mais conveniente (ou similar). No entanto, essas estruturas requerem mais recursos (aumentando o número de operações para provar o mesmo na ordem das dezenas) para execução.
  3. Herança e Polimorfismo: O Cairo não tem os conceitos de herança e polimorfismo. Embora os contratos possam ser estendidos importando funções e variáveis de armazenamento específicas, os conceitos muito usados da programação orientada a objetos requerem um pouco de pensamento "fora da caixa".

Cairo compila para Sierra

Um passo a ser observado é que, quando você escreve um contrato inteligente com o Cairo, ele é primeiro convertido em código Sierra, que deve ser publicado na rede. O código Sierra é uma abstração sobre o código Assembly bruto do Cairo (CASM) interpretado pela Máquina Virtual Cairo. A compilação do código Cairo para Sierra envolve o código Cairo com algumas medidas de segurança, a mais importante das quais é um mecanismo para evitar ataques DoS.

De acordo com a documentação da Starknet, "Uma propriedade crucial de cada camada 2 descentralizada é que os sequenciadores têm garantia de serem compensados pelo trabalho que fazem. A noção de transações revertidas é um bom exemplo: mesmo que a transação do usuário falhe durante a execução, o sequenciador deve ser capaz de incluí-la em um bloco e cobrar taxas de execução até o ponto de falha.”

No entanto, às vezes um usuário pode escrever uma linha de código ou incluir uma transação, provando que a execução é impossível. Por exemplo, a declaração assert 1 == 0 é uma declaração Cairo válida; no entanto, incluir essa execução em uma prova criptográfica não é possível, pois essa declaração é falsa e se traduz em restrições polinomiais que não são satisfatórias. Portanto, o Sierra adiciona uma camada de segurança que garante que até mesmo transações revertidas improváveis sejam cobradas. Isso atenua o potencial de um ataque DoS no sequenciador e satisfaz seus incentivos econômicos do sequenciador.

Comparando o Cairo com o Solidity

Agora temos uma ideia dos tipos básicos, funções e estruturas do Cairo. Vamos compará-los com seus equivalentes em Solidity para traçar alguns paralelos entre as duas linguagens de contrato inteligente. (Lembre-se de que o Cairo também pode ser usado para escrever código que não é de contrato inteligente, que pode ser usado para criar programas comprováveis. No entanto, isso está fora do nosso escopo atual de discussão.)

Nota: A partir deste ponto, toda discussão sobre o Cairo se refere ao Cairo 1. O Cairo 0 não é mais recomendado como a linguagem principal para escrever contratos inteligentes na Starknet.

Tipos do Cairo

Aqui está a lista de alguns tipos fundamentais em Cairo:

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*S4gXlmfh0bJ5TXLfPDjWZw.png

Como você pode ver na lista acima (acabamos de adicionar números inteiros e temos também o dicionário), a partir do Cairo 1, foram adicionados inteiros sem sinal ao Cairo, semelhantes aos seus equivalentes em Solidity. Embora o uso de inteiros possa ser menos eficaz em termos de custo para o sequenciador do que usar diretamente os elementos de corpo (felt), a integração de inteiros no Cairo promete simplificar a vida dos desenvolvedores.

Além disso, o uso de Arrays é muito semelhante à sintaxe em Rust, e eles são semelhantes em lógica aos do Solidity.

Funções do Cairo

As funções do Cairo podem ser dos seguintes tipos:

  • Interna (internal)
  • Externa (external)
  • De visualização (view)
  • Construtora (constructor)

Por padrão, todas as funções de contrato são consideradas de tipo internal (tais funções só podem ser chamadas de dentro do contrato - um tanto semelhantes às funções privadas em outras linguagens).

Funções de tipo external estão abertas ao mundo e podem ser chamadas por outros contratos inteligentes também - incluindo contas. (Viva, abstração de conta!)

As funções view são um tipo de função externa que só podem ler o estado da cadeia. Funções de visualização não podem modificar o estado da cadeia.

Constructor é outro atributo de funções em Cairo dado a... construtores de um contrato inteligente!

Agora, vamos comparar a sintaxe da declaração de funções entre Cairo e Solidity:

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*ikjeY0wtqaO11wfOumV1ug.png

Vamos olhar em mais detalhes algumas das principais diferenças:

  1. A palavra-chave utilizada para declarar uma função no Cairo é fn, enquanto function é utilizada no Solidity.
  2. Os tipos de função são declarados antes da palavra-chave da função em Cairo (#[view]), mas em Solidity, o formato é diferente (veja acima).
  3. Na linguagem de programação Cairo, a sintaxe para declarar valores de retorno envolve o uso do símbolo . Por outro lado, em Solidity, a palavra-chave returns é usada para denotar valores de retorno.

Módulos no Cairo

Os módulos no Cairo servem para agrupar funcionalidades relacionadas dentro de um espaço de nome. A palavra-chave mod é usada para definir um módulo, seguido pelo nome do módulo e um bloco de código que inclui funções e outras declarações. Os módulos podem importar outros módulos e fazer uso de suas funcionalidades.

Eles são semelhantes às bibliotecas em outras linguagens e, em Solidity, os módulos podem ser comparados à herança de contratos.

https://miro.medium.com/v2/resize:fit:720/0*ZSsHUwERYOlLL9zG

Por exemplo, no código acima, os módulos starknet e array são importados. A sintaxe difere das declarações import em Solidity ou do recurso de herança, que usa a palavra-chave is (veja aqui). Observe que a palavra-chave use torna todas as funções do módulo importado acessíveis dentro do módulo que está importando em Cairo.

Arrays no Cairo

Usar arrays no Cairo 1.0 se tornou mais fácil, pois as manipulações do array dinâmico são possíveis com as funções exportadas do módulo de array, como append, array_at, e array_len.

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*rDBZP_LCBc1Xc35MVYhvVw.png

Exemplo de Contrato Inteligente do Cairo

Agora que entendemos o conjunto de tipos e funções em Cairo, vamos revisar um exemplo de código de contrato ERC20 em Cairo. Um contrato ERC20 é um contrato inteligente padrão para os tokens que as pessoas possuem na cadeia. Ele permite que os usuários transfiram tokens uns para os outros, verifiquem saldos para usuários e aprovem transferências para outra entidade. Aqui está o nosso contrato:

Nota: A sintaxe do Cairo 1 está mudando um pouco e será atualizada ainda este ano (2023). Por favor, veja este post para mais detalhes.

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*G9FwaCojX2j9F3xemwz_HQ.png

O código acima é baseado em https://github.com/argentlabs/starknet-build/blob/main/cairo1.0/examples/erc20/ERC20.cairo

Vamos olhar em detalhes algumas das partes mais importantes.

As linhas 1 e 2 inicializam e dão nome ao contrato inteligente

#[contract]

mod ERC20 {
Enter fullscreen mode Exit fullscreen mode

A linha 4 importa a função get_caller_address do módulo starknet. A função get_caller_address() retorna o endereço do contrato que chamou a função.

use starknet::get_caller_address;
Enter fullscreen mode Exit fullscreen mode

As linhas 7 a 14 definem uma estrutura (similar a struct em Solidity) que é usada mais tarde no código.

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*00Ov1iupLJjTapMHBzXREg.png

As linhas 20 e 21 definem um evento Transfer que é emitido sempre que o token ERC20 é transferido. Eventos fornecem uma maneira eficiente de rastrear atividades do contrato/mudanças de estado, permitindo assim que ouvintes externos reajam de acordo.

#[event]

fn Transfer(from_: felt, to: felt, value: u256) {}
Enter fullscreen mode Exit fullscreen mode

As linhas 36 a 54 contêm uma função construtora (a função que é chamada quando o contrato é implantado) e uma função de visualização que lê a variável de armazenamento name e retorna seu valor ao usuário.

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*Ne9ewJsm8II9F7Tjwf5_Cw.png

As linhas 97 a 101 definem uma função externa (discutida anteriormente) que é usada para transferir tokens ERC20 de uma conta para outra. Esta função chama a função transfer_helper() abaixo, que também emite o evento Transfer() definido acima.

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*xyzAaUD9mJ9JJ_AhL7rZSA.png

Conclusão

Se você está confortável com o Solidity, agora deve ser um ótimo começo para entender como a Starknet funciona, as diferenças entre o Cairo e o Solidity e como ler contratos inteligentes básicos do Cairo.

Para o próximo passo em sua jornada de desenvolvimento no Cairo, consulte a documentação do Cairo, registre-se no Cairo Basecamp ou navegue pelos tutoriais.

Artigo original publicado por StarkWare. Traduzido por Paulinho Giovannini.

Top comments (0)