WEB3DEV

Cover image for Comparando Padrões de Capacidade de Atualização do Solidity
Panegali
Panegali

Posted on

Comparando Padrões de Capacidade de Atualização do Solidity

Proxy Transparente, Armazenamento Eterno (Eternal), Armazenamento Diamante (Diamond), Multifacetas.

Pode-se encontrar esses termos ao tentar construir contratos de alta qualidade que possam resistir ao teste do tempo, atualizando conforme necessário.

Este resumo tem como objetivo desmembrá-los, como eles interagem entre si e como você pode começar a usá-los. Ele não tem como objetivo fornecer um tutorial aprofundado sobre cada um deles.

Proxy transparente

https://docs.openzeppelin.com/upgrades-plugins/1.x/

Essa é a abordagem usada pelo plug-in de atualizações do OpenZeppelin. É uma solução simples para capacidade de atualização, onde você pode começar a implantar contratos inteligentes atualizáveis ​​com conhecimento mínimo da estrutura de armazenamento do Solidity ou proxies, pois o plug-in faz um ótimo trabalho ao abstraí-los.

Ao implantar um contrato atualizável usando o plug-in, o que realmente acontece nos bastidores é que um contrato de proxy é implantado, responsável por armazenar todo o estado. O contrato de implementação que você mesmo escreveu está oculto atrás do proxy e não possui nenhum estado.

Você pode estar se perguntando, como a implementação pode não manter nenhum estado? Eu tenho variáveis ​​de armazenamento na minha implementação. Bem, o uso da delegatecall pelo proxy significa que quaisquer variáveis ​​de armazenamento declaradas em um contrato de implementação são indicações para o local de armazenamento real que é o proxy.

Isso significa que você pode alterar o contrato de implementação mantendo o estado, pois o contrato de implementação é apenas um monte de indicações de armazenamento, enquanto o armazenamento em si está no contrato de proxy.

Uma limitação da abordagem de proxy transparente é que deve-se tomar cuidado ao atualizar contratos, pois quaisquer variáveis ​​de armazenamento adicionadas ao contrato de implementação durante uma atualização não devem se sobrepor aos contratos de implementação anteriores.

Isso pode ser difícil, pois a EVM normalmente usa um espaço de armazenamento linear, onde as variáveis ​​declaradas sequencialmente terão locais sequenciais no armazenamento. Felizmente, o plug-in OpenZeppelin evita erros detectando esses erros antecipadamente. Portanto, esta é a melhor abordagem se o seu caso de uso não for extremamente complexo.

Armazenamento Eterno (Eternal)

https://fravoll.github.io/solidity-patterns/eternal_storage.html

Em março de 2020, foi lançada a versão 0.6.4 do Solidity, permitindo que você escolha onde armazenar suas variáveis ​​de armazenamento.

O que isso significa é que você não precisa mais se preocupar com o espaço de armazenamento linear se não quiser. Esse espaço de armazenamento linear é problemático ao fazer atualizações, pois você precisa seguir regras cuidadosas ao adicionar novas variáveis ​​de armazenamento. Em vez disso, você pode usar o armazenamento eterno, que permite armazenar em qualquer lugar.

Geralmente, a abordagem é que o local que você escolhe para armazenar suas variáveis ​​é o hash da 'chave' que você atribui à variável. Por exemplo, se eu quiser armazenar um contador em algum lugar, posso dar a chave 'contador'. Deve-se tomar cuidado ao usar uma chave exclusiva, pois conflitos com outros nomes de chave resultariam em indicações de armazenamento substituindo umas às outras.

Exemplo de configuração e obtenção:

// definir
EternalStorage.setUintValue('MY_SPECIAL_KEY', 10);
// obter
uint256 val = EternalStorage.getUintValue('MY_SPECIAL_KEY');
Enter fullscreen mode Exit fullscreen mode

Armazenamento Diamante (Diamond)

https://eips.ethereum.org/EIPS/eip-2535#diamond-storage

Isso usa um padrão semelhante ao armazenamento Eterno, mas usa estruturas para acessar as variáveis ​​necessárias em vez de 'chaves' baseadas em string.

Por exemplo, você pode fazer algo assim para definir e obter um inteiro:

DiamondStorage.MySpecialStruct storage mySpecialStruct = DiamondStorage.mySpecialStruct();
// definir
mySpecialStruct.myValue = 10;
// obter
uint256 val = mySpecialStruct.myValue;
Enter fullscreen mode Exit fullscreen mode

O benefício do padrão Diamante é que a sua struct pode ter vários valores e só precisa ser buscada uma vez, enquanto no padrão Eterno, cada item que você deseja definir ou obter precisa ser feito explicitamente e não pode ser agrupado facilmente.

Além disso, você precisa ter um setter/getter explícito para cada tipo que deseja suportar ao usar o padrão Eterno. Além disso, o padrão Diamante pode ser estendido para usar o padrão AppStorage, o que reduz a versatilidade de obtenção e configuração.

Diamantes (proxy multifacetado)

https://blog.zkga.me/dark-forest-and-the-diamond-standard

https://eips.ethereum.org/EIPS/eip-2535

Lembre-se que com um proxy transparente, temos um único proxy, com um único contrato de implementação. Com o padrão diamante, você pode ter um único ponto de contrato de proxy para várias implementações. Por que isso é útil?

Bem, vamos imaginar um contrato ERC20 que usa o padrão diamante. Você poderia ter a funcionalidade de cunhar e a funcionalidade de transferência em contratos separados. Eles seriam costurados por um único contrato diamante.

Na realidade, não faríamos isso, porque a cunhagem e a transferência são logicamente semelhantes e, portanto, agrupadas no mesmo contrato.

Mas se, por exemplo, você quisesse toda a funcionalidade de um ERC20 e toda a funcionalidade de algum outro contrato arbitrário sem usar herança, exposta por meio de um único endereço de contrato, você poderia usar um contrato Diamante para fazer isso. Isso é ótimo para grandes projetos em Solidity que têm vários contratos que precisam ser expostos por um único endereço de contrato.


Artigo escrito por Zoraiz Mahmood e traduzido por Marcelo Panegali

Oldest comments (0)