A seguir, examinaremos detalhadamente as principais características do idioma Move e quais são suas principais diferenças com outro idioma já popular para contratos inteligentes - Solidity (na plataforma Ethereum). O material é baseado no estudo de um white paper on-line de 26 páginas disponível.
1. Introdução
Move é uma linguagem executável de código de bytes usada para executar transações do usuário e contratos inteligentes. Preste atenção a dois pontos:
- Enquanto o Move é uma linguagem de bytecode que pode ser executada diretamente na máquina virtual Move, o Solidity (linguagem de contrato inteligente no Ethereum) é uma linguagem de nível superior que é compilada primeiro no bytecode antes de ser executada no EVM (Ethereum Virtual Machine )
- O Move pode ser usado não apenas para a implementação de contratos inteligentes, mas também para transações de usuários (mais sobre isso mais adiante), enquanto o Solidity é uma linguagem apenas para contratos inteligentes.
Tradução feita pela equipe do projeto do protocolo INDEX. Anteriormente, traduzimos muito material que descreve o projeto Libra , agora é a vez de analisar o idioma Move um pouco mais profundamente. A tradução foi feita em conjunto com coolsiuUm recurso importante do Move é a capacidade de definir tipos de recursos personalizados com semântica lógica linear: um recurso nunca pode ser copiado ou excluído implicitamente, apenas movido. Funcionalmente, isso é semelhante aos recursos da linguagem Rust. Os valores em Rust podem ser atribuídos apenas a um nome por vez. A atribuição de um valor a outro nome o torna inacessível sob o nome anterior.

Por exemplo, o seguinte fragmento de código gerará um erro:
Uso do valor movido 'x'. Isso ocorre porque não há coleta de lixo no Rust. Quando as variáveis ficam fora do escopo, a memória à qual elas se referem também é liberada. Simplificando, pode haver apenas um "proprietário" dos dados. Neste exemplo,
x é o proprietário original e
y se torna o novo proprietário.
Leia mais sobre esse comportamento aqui .
Representação de ativos digitais em sistemas abertos
Há duas propriedades de ativos físicos que são difíceis de representar digitalmente:
- Raridade (escassez, no original - escassez). A quantidade de ativos (emissão) no sistema deve ser controlada. A duplicação de ativos existentes deve ser proibida e a criação de novos é uma operação privilegiada.
- Controle de acesso . O participante do sistema deve poder proteger ativos com políticas de controle de acesso.
Essas duas características, que são naturais para ativos físicos, precisam ser implementadas para objetos digitais, se quisermos considerá-los ativos. Por exemplo, um metal raro - tem um déficit natural e somente você tem acesso a ele (segurando em suas mãos, por exemplo) e pode vendê-lo ou gastá-lo.
Para ilustrar como chegamos a essas duas propriedades, vamos começar com as seguintes frases:
Proposição 1: A regra mais simples, sem escassez e controle de acesso

- G [K]: = n significa atualizar o número acessível pela chave K no estado global da blockchain com o novo valor n .
- A transação "Alice, 100" significa definir o saldo da conta de Alice como 100.
A solução acima tem vários problemas sérios:
- Alice pode receber um número ilimitado de moedas simplesmente enviando a transação iceAlice, 100⟩.
- As moedas que Alice envia para Bob são inúteis, pois Bob poderia enviar um número ilimitado de moedas usando a mesma técnica.
Proposta nº 2: leve em consideração o déficit

Agora estamos monitorando a situação para que o número de moedas
Ka seja pelo menos
n antes da transação de transferência. No entanto, embora isso resolva o problema da escassez, não há informações sobre quem pode enviar as moedas de Alice (até agora todos podem fazer isso, o principal é não violar a regra dos limites de quantidade).
Proposição 3: Combinando déficit e controle de acesso

Resolvemos esse problema com o
mecanismo de assinatura digital
confirm_sig antes de verificar o saldo, o que significa que Alice usa sua chave privada para assinar a transação e confirmar que possui suas moedas.
Linguagens de programação Blockchain
As linguagens blockchain existentes enfrentam os seguintes problemas (todos foram resolvidos no Move (nota:
infelizmente, o autor do artigo apenas apela ao Ethereum em suas comparações, portanto, você deve levá-los apenas nesse contexto. Por exemplo, a maioria dos itens a seguir também é resolvida na EOS )):
Representação indireta de ativos . Um ativo é codificado usando um número inteiro, mas um valor inteiro não é o mesmo que um ativo. De fato, não há tipo ou valor representando bitcoin / ether / <Any Coin>! Isso torna os programas de gravação que usam ativos difíceis e propensos a erros. Padrões como a transferência de ativos para / de procedimentos ou o armazenamento de ativos em estruturas requerem suporte especial ao idioma.
O déficit não é expansível . A linguagem representa apenas um ativo escasso. Além disso, os remédios contra o déficit são conectados diretamente à semântica da própria linguagem. Um desenvolvedor, se ele deseja criar um ativo do usuário, deve monitorar cuidadosamente todos os aspectos do recurso. Estes são apenas os problemas dos contratos inteligentes da Ethereum.
Os usuários emitem seus ativos, tokens padrão do ERC-20, usando números inteiros para determinar o custo e o problema total. Sempre que novos tokens são criados, o código do contrato inteligente deve verificar independentemente a conformidade com as regras de emissão. Além disso, a representação indireta de ativos leva, em alguns casos, a erros graves - duplicação, duplicação de gastos ou até uma completa perda de ativos.
Falta de controle de acesso flexível . A única política de controle de acesso atualmente em uso é um esquema de assinatura usando criptografia assimétrica. Assim como a proteção contra déficit, as políticas de controle de acesso estão profundamente embutidas na semântica da linguagem. Mas como expandir a linguagem para permitir que os programadores definam suas próprias políticas de controle de acesso geralmente é uma tarefa não trivial.
Isso também se aplica ao Ethereum, onde contratos inteligentes não têm suporte de criptografia nativa para controle de acesso. Os desenvolvedores devem prescrever manualmente o controle de acesso, por exemplo, usando o modificador onlyOwner.
Embora eu seja um grande fã do Ethereum, acredito que as propriedades dos ativos devem ser suportadas nativamente pelo idioma por razões de segurança. Em particular, transferir o Ether para um contrato inteligente envolve despacho dinâmico, o que levou ao surgimento de uma nova classe de erros conhecidos como vulnerabilidades de reentrada. O despacho dinâmico aqui significa que a lógica da execução do código será determinada no tempo de execução (dinâmico) e não no tempo de compilação (estático).
Assim, no Solidity, quando o contrato A chama a função do contrato B, o contrato B pode executar um código que não foi fornecido pelo desenvolvedor do contrato A, o que pode levar a
vulnerabilidades de reentrada (o contrato A executa acidentalmente a função do contrato B para sacar dinheiro antes da dedução real saldos de conta).
Mover conceitos básicos de design de idioma
Recursos de primeira ordem
Falando em um nível superior, a interação entre módulos / recursos / procedimentos na linguagem Move é muito semelhante às relações entre classes / objetos e métodos nas linguagens OOP.
Os módulos no Move são semelhantes aos contratos inteligentes em outras blockchains. O módulo declara os tipos de recursos e procedimentos que definem as regras para criar, destruir e atualizar os recursos declarados. Mas tudo isso são apenas convenções ("
jargões ") no Move. Um pouco mais tarde ilustraremos esse ponto.
Flexibilidade
O Move adiciona flexibilidade ao Libra através de scripts. Cada transação no Libra inclui um script, que é realmente o principal procedimento de transação. O script pode executar uma ação especificada, por exemplo, pagamentos de acordo com a lista especificada de destinatários ou reutilizar outros recursos - por exemplo, chamando um procedimento no qual a lógica geral é especificada. É por isso que os scripts de transação do Move oferecem mais flexibilidade. O script pode usar comportamentos únicos e repetitivos, enquanto o Ethereum pode executar apenas scripts repetitivos (chamando um método de contrato inteligente chamando um método). O motivo pelo qual é chamado de "múltiplo" é porque as funções de um contrato inteligente podem ser executadas várias vezes. (nota:
o momento é muito delicado aqui. Por um lado, os scripts de transação na forma de pseudo-bytecode também estão no Bitcoin. Por outro lado, como eu o entendo, o Move expande esse idioma, de fato, para o nível de uma linguagem de contrato inteligente completa ).
Segurança
O formato executável Move é bytecode, que, por um lado, é um idioma de nível superior ao assembler, mas inferior ao código fonte. O bytecode é verificado na cadeia quanto à disponibilidade de recursos, tipos e segurança de memória usando o verificador de bytecode e, em seguida, executado pelo intérprete. Essa abordagem permite que o Move forneça segurança específica ao código-fonte, mas sem o processo de compilação e a necessidade de adicionar um compilador ao sistema. Tornar o Move uma linguagem de bytecode é uma solução realmente boa. Não há necessidade de compilá-lo a partir da fonte, como é o caso do Solidity, não há necessidade de se preocupar com possíveis falhas ou ataques na infraestrutura do compilador.
Verificabilidade
Nosso objetivo é realizar verificações o mais fácil possível, pois tudo isso entra em cadeia (nota:
on-line, no processo de cada transação, portanto, qualquer atraso leva a uma desaceleração de toda a rede ); no entanto, o design da linguagem está inicialmente pronto para uso e meios fora da cadeia de verificação estática. Embora isso seja mais preferível, até agora o desenvolvimento de ferramentas de verificação (como um kit de ferramentas separado) foi adiado para o futuro, e agora apenas a verificação dinâmica em tempo de execução (on-chain) é suportada.
Modularidade
Os módulos Move fornecem abstração de dados e localizam operações críticas nos recursos. O encapsulamento fornecido pelo módulo, combinado com a proteção fornecida pelo sistema de tipo Mover, garante que as propriedades definidas para os tipos de módulo não possam ser violadas pelo código fora do módulo. Esse é um projeto de abstração bem pensado, o que significa que os dados dentro do contrato só podem ser alterados dentro da estrutura do contrato, mas não de fora.

Mover revisão
Um script de transação de exemplo demonstra que ações maliciosas ou imprudentes de um programador fora de um módulo não podem violar a segurança dos recursos do módulo. A seguir, veremos exemplos de como os módulos, recursos e procedimentos são usados para programar o blockchain Libra.
Pagamentos ponto a ponto

A quantidade de moedas especificada na quantidade será transferida do saldo do remetente para o destinatário.
Existem vários novos pontos (destacados em vermelho):
- 0x0 : endereço da conta em que o módulo está armazenado
- Moeda : nome do módulo
- Moeda : tipo de recurso
- O valor da moeda retornado pelo procedimento é um valor de recurso cujo tipo é 0x0.Currency.Coin
- move () : o valor não pode ser usado novamente
- copy () : o valor pode ser usado posteriormente
Analisamos o código: na primeira etapa, o remetente chama um procedimento chamado
retire_from_sender a partir do módulo armazenado em
0x0.Currency . No segundo estágio, o remetente transfere os fundos para o destinatário, movendo o valor do recurso de moeda para o procedimento de depósito do módulo
0x0.Currency .
Aqui estão três exemplos de erros de código que serão rejeitados por verificações:
Duplicação de fundos alterando a chamada para mover (moeda) para copiar (moeda) . Os recursos podem ser movidos apenas. Tentar duplicar a quantidade de um recurso (por exemplo, chamando
copy (coin) no exemplo acima) resultará em um erro ao verificar o bytecode.
Reutilização de fundos especificando o movimento (moeda) duas vezes . Adicionar a linha
0x0.Currency.deposit (copy (some_other_payee), move (coin)) para o exemplo acima permitirá que o remetente "gaste" moedas duas vezes - a primeira vez com o beneficiário e a segunda com
some_other_payee . Esse é um comportamento indesejável, impossível com um ativo físico. Felizmente, o Move rejeitará este programa.
Perda de fundos devido a falha no movimento (moeda) . Se você não mover o recurso (por exemplo, excluindo a linha que contém o
movimento (moeda) ), será gerado um erro ao verificar o bytecode. Isso protege os programadores do Move contra perda acidental ou maliciosa de fundos.
Módulo de moeda

Cada conta pode conter 0 ou mais módulos (representados como retângulos) e um ou mais valores de recursos (representados como cilindros). Por exemplo, uma conta em
0x0 contém um módulo
0x0.Currency e um valor de recurso do tipo
0x0.Currency.Coin . A conta em
0x1 possui dois recursos e um módulo; A conta em
0x2 possui dois módulos e um valor de recurso.
Alguns pontos:
- O script de transação é atômico - completamente executado, ou nem um pouco.
- Um módulo é um código de longa duração disponível globalmente.
- O estado global está estruturado como uma tabela de hash, onde a chave será o endereço da conta
- As contas podem conter não mais que um valor de recurso desse tipo e não mais que um módulo com um determinado nome (uma conta em 0x0 não pode conter um recurso adicional 0x0.Currency.Coin ou outro módulo chamado Currency )
- O endereço do módulo declarado faz parte do tipo ( 0x0.Currency.Coin e 0x1.Currency.Coin são tipos separados que não podem ser usados de forma intercambiável)
- Os programadores podem armazenar várias instâncias desse tipo de recurso na conta, definindo seu recurso personalizado - ( recurso TwoCoins {c1: 0x0.Currency.Coin, c2: 0x0.Currency.Coin} )
- Você pode se referir a um recurso por seu nome sem conflitos, por exemplo, pode se referir a dois recursos usando TwoCoins.c1 e TwoCoins.c2 .
Anúncio de recurso de moeda

Um módulo chamado
Currency e um tipo de recurso chamado
CoinAlguns pontos:
- Coin é uma estrutura de campo único do tipo u64 (número inteiro não assinado de 64 bits)
- Somente os procedimentos do módulo Moeda podem criar ou destruir valores de moeda .
- Outros módulos e scripts podem gravar ou referenciar o campo de valor somente por meio de procedimentos abertos fornecidos pelo módulo.
Implementação de Depósito

Este procedimento usa o recurso
Coin como entrada e o combina com o recurso
Coin armazenado na conta do destinatário:
- Destruindo o recurso de entrada Coin e registrando seu valor.
- Obter um link para um recurso de moeda exclusivo armazenado na conta do destinatário.
- Alterando o valor da quantidade de moeda pelo valor passado no parâmetro quando o procedimento é chamado.
Alguns pontos:
- Desembalar, BorrowGlobal - procedimentos internos
- Descompactar <T> é a única maneira de excluir um recurso do tipo T. O procedimento leva o recurso à entrada, destrói-o e retorna o valor associado aos campos do recurso.
- BorrowGlobal <T> aceita o endereço como entrada e retorna um link para uma instância exclusiva de T publicada (de propriedade) por este endereço
- & mut Coin é um link para o recurso Coin
Implementar retire_from_sender

Este procedimento:
- Obtém um link para um recurso de moeda exclusivo vinculado à conta do remetente
- Diminui o valor do recurso Coin por referência à quantidade especificada
- Cria e retorna um novo recurso de moeda com um saldo atualizado.
Alguns pontos:
- Qualquer depósito pode ser chamado por qualquer pessoa, mas o retirada_from_sender tem acesso apenas às moedas da conta de chamada
- GetTxnSenderAddress é semelhante ao msg.sender no Solidity
- RejectUnless é semelhante ao requerido no Solidity. Se essa verificação falhar, a transação será interrompida e todas as alterações serão revertidas.
- O pacote <T> também é um procedimento interno que cria um novo recurso do tipo T.
- Como descompactar <T> , o pacote <T> só pode ser chamado dentro do módulo em que o recurso T é descrito
Conclusão
Examinamos as principais características da linguagem Move, comparamos com o Ethereum e também nos familiarizamos com a sintaxe básica dos scripts. Em conclusão, eu recomendo olhar o
white paper original . Inclui muitos detalhes sobre os princípios do design da linguagem de programação, bem como muitos links úteis.