Como escrever um contrato inteligente em WebAssembly na rede Ontology? Parte 1: Rust

Como escrever um contrato inteligente em WebAssembly na rede Ontology? Parte 1: Rust

A tecnologia Ontology Wasm reduz o custo de migração de contratos inteligentes dApp com lógica de negócios complexa para blockchain, enriquecendo significativamente o ecossistema dApp.

Atualmente Ontology Wasm suporta simultaneamente o desenvolvimento em Rust e C++. A linguagem Rust oferece melhor suporte para Wasm, e o bytecode gerado é mais simples, o que pode reduzir ainda mais o custo das chamadas de contrato. Portanto, como usar Rust para desenvolver um contrato na rede Ontology?

Desenvolvendo um contrato WASM com Rust

Criando um contrato

Cargo é uma boa ferramenta de criação de projetos e gerenciamento de pacotes ao desenvolver programas em Rust, ajudando os desenvolvedores a organizarem melhor a interação entre o código e bibliotecas de terceiros. Para criar um novo contrato Ontology Wasm, basta executar o seguinte comando:

Como escrever um contrato inteligente em WebAssembly na rede Ontology? Parte 1: Rust

A estrutura do projeto que ela gera:

Como escrever um contrato inteligente em WebAssembly na rede Ontology? Parte 1: Rust

O arquivo Cargo.toml é utilizado para configurar as informações básicas do projeto e as informações da biblioteca dependente. A seção [lib] no arquivo deve ser definida para crate-type = ["cdylib"]. O arquivo lib.rs é usado para escrever a lógica do contrato. Além disso, você deve adicionar os parâmetros de dependências na seção [dependencies] do arquivo de configuração Cargo.toml:

Como escrever um contrato inteligente em WebAssembly na rede Ontology? Parte 1: Rust

Com esta dependência, os desenvolvedores podem chamar interfaces que interagem com a blockchain Ontology e ferramentas como o parâmetro de serialização.

Função de entrada do contrato

Cada programa tem uma função de entrada, como a função main que normalmente vemos, mas um contrato não possui uma função main. Ao desenvolver um contrato Wasm usando Rust, a função invoke é utilizada por padrão como função de entrada para o uso do contrato. O nome da função em Rust será obscuro ao compilar o código-fonte Rust em bytecode, que pode ser executado pela máquina virtual. Para evitar que o compilador gere código excessivo e reduzir o tamanho do contrato, a função invoke adiciona a anotação #[no_mangle].

Como a função invoke recebe parâmetros para executar a transação?

A biblioteca ontio_std fornece a função runtime::input() para obter os parâmetros para a execução de transações. Os desenvolvedores podem usar o ZeroCopySource para desserializar o array de bytes recebido. O primeiro array de bytes lido é o nome do método invoke, seguido pelos parâmetros do método.

Como o resultado da execução do contrato é retornado?

A função runtime::ret, que é fornecida pela biblioteca ontio_std, retorna o resultado da execução do método.

A função invoke concluída se parece com o seguinte:

Como escrever um contrato inteligente em WebAssembly na rede Ontology? Parte 1: Rust

Serialização e desserialização de dados do contrato

Durante o desenvolvimento de contratos, os desenvolvedores sempre encontram problemas de serialização e desserialização, especificamente em como armazenar um tipo de dado struct no banco de dados e como desserializar um array de bytes lido do banco de dados para obter um tipo de dado struct.

A biblioteca ontio_std fornece interfaces de codificador e decodificador para serialização e desserialização de dados. Os campos da estrutura struct também implementam as interfaces de codificador e decodificador, de modo que a estrutura possa ser serializada e desserializada. Instâncias da classe Sink são necessárias ao serializar diferentes tipos de dados. Uma instância da classe Sink possui um campo do tipo set chamado buf, que armazena dados do tipo byte, enquanto todos os dados serializados são mantidos em buf.

Para dados de comprimento fixo (por exemplo: byte, u16, u32, u64, etc.), os dados são convertidos diretamente em um array de bytes e, em seguida, salvos em buf; para dados de comprimento variável, primeiro é necessário serializar o comprimento e depois os dados (por exemplo, números inteiros sem sinal de tamanho desconhecido, incluindo u16, u32 ou u64, etc.).

A desserialização é o oposto direto. Para cada método de serialização, há um método correspondente de desserialização. A desserialização requer o uso de instâncias da classe Source. Essa instância da classe possui dois campos: buf e pos. Buf é usado para armazenar os dados que serão desserializados, enquanto pos é usado para armazenar a posição atual da leitura. Quando um tipo específico de dado é lido, se você souber seu comprimento, poderá lê-lo diretamente; para dados de comprimento desconhecido, primeiro leia o comprimento e, em seguida, leia o conteúdo.

Acesso e atualização de dados na cadeia

Ontology-wasm-cdt-rust — encapsulou o método operacional de trabalho com dados na cadeia, que é conveniente para os desenvolvedores realizarem operações como adicionar, remover, modificar e solicitar dados na cadeia da seguinte forma:

  • database::get(chave) — é utilizado para solicitar dados da cadeia, onde a chave solicita a implementação da interface AsRef;
  • database::put(chave, valor) — é utilizado para armazenar dados na rede. A chave solicita a execução da interface AsRef, enquanto o valor solicita a implementação da interface Encoder;
  • database::delete(chave) — é utilizado para remover dados da cadeia, onde a chave solicita a implementação da interface AsRef.

Teste de contrato

Quando os métodos do contrato são implementados, precisamos de acesso aos dados na cadeia e de uma máquina virtual correspondente para executar o bytecode do contrato, portanto, geralmente é necessário implantar o contrato na cadeia para teste. Mas esse método de teste é problemático. Para facilitar o teste de contratos para os desenvolvedores, a biblioteca ontio_std fornece um módulo mock para testes. Este módulo simula dados na cadeia, facilitando para os desenvolvedores a realização de testes unitários dos métodos no contrato. Exemplos específicos podem ser encontrados aqui.

Depuração de contrato

console::debug(mensagem) exibe informações de depuração durante a depuração do contrato. A informação mensagem será registrada no arquivo de log do nó. É condição obrigatória que o nível de log seja definido para modo de depuração quando a test-nó local Ontology estiver em execução.

runtime::notify(mensagem) exibe informações de depuração apropriadas durante a depuração do contrato. Este método irá salvar as informações enviadas na cadeia e podem ser consultadas a partir da cadeia usando o método getSmartCodeEvent.

Este artigo foi traduzido pela equipe da Hashrate & Shares especialmente para a OntologyRussia. clique

Você é desenvolvedor? Junte-se à nossa comunidade técnica em Discord. Além disso, dê uma olhada no Centro de Desenvolvedores em nosso site, onde você pode encontrar ferramentas de desenvolvedor, documentação e muito mais.

Ontology

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster