WEB3DEV

Cover image for Armadilhas de contratos atualizáveis | BlockAudit
Adriano P. Araujo
Adriano P. Araujo

Posted on

Armadilhas de contratos atualizáveis | BlockAudit

Apoiar a criação de contratos atualizáveis é uma tendência comum na arquitetura de contratos inteligentes. Os métodos agora usados para atualizar contratos têm desvantagens, aumentam bastante a complexidade do contrato e, eventualmente, criam erros. Neste post, abordaremos profundamente como analisamos as atuais metodologias de atualização de contratos inteligentes, o que descobrimos serem suas falhas práticas e o que sugerimos para contratos que precisam de atualizações.

Uma visão geral dos contratos atualizáveis

No mais comum, existem duas “famílias” de projetos para contratos inteligentes atualizáveis:

  • Lógica e dados são tratados em diferentes contratos na separação de dados. O contrato de dados pertence e é invocado pelo contrato lógico.

  • Proxies baseados em chamadas delegadas, em que o contrato de dados (o proxy) invoca o contrato lógico usando um delegatecall , mantendo a lógica e os dados em diferentes contratos também.

A simplicidade do esquema de separação de dados é um benefício. Ao contrário do padrão delegatecall, ele não precisa do mesmo conhecimento básico. Recentemente, o padrão delegatecall chamou muita atenção.

Padrão de separação de dados

Lógica e dados são mantidos em contratos diferentes pelo padrão de separação de dados. Se necessário, o contrato lógico, que é o proprietário do contrato de dados, pode ser atualizado. Não há intenção de atualizar o contrato de dados. Seu conteúdo só pode ser alterado pelo proprietário.

Considere esses dois fatores em particular ao pensar nesse padrão: procedimentos de armazenamento e atualização de dados.

Estratégia de armazenamento de dados

Você pode adotar uma arquitetura direta, na qual o contrato de dados mantém as variáveis com seus getters e setters, se as variáveis necessárias ao longo de uma atualização permanecerem constantes. Os montadores só devem ser alcançáveis pelo proprietário do contrato:

Exemplo de armazenamento de dados (usando apenas o modificador do proprietário)

Você deve fazer uma determinação precisa das variáveis de estado necessárias. Como os contratos baseados em tokens ERC20 precisam apenas economizar seus saldos, essa estratégia é apropriada para eles.

Essas variáveis persistentes adicionais podem ser mantidas em um contrato de dados separado, caso uma atualização posterior as exija. Você pode dividir os dados entre diferentes contratos, mas isso exigirá mais autorização e chamadas lógicas de contrato. A taxa extra pode ser aceitável se você geralmente não planeja atualizar o contrato.

Par de valores-chave

Uma alternativa ao método direto de armazenamento de dados mencionado acima é um sistema de pares de valores-chave. Embora mais complexo, também é mais evolutivamente receptivo. Você pode especificar um mapeamento de um valor de chave bytes32 para cada tipo de variável base, por exemplo:

Exemplo de armazenamento de valor-chave (usando apenas o modificador do proprietário )

Os riscos do padrão de separação de dados

O padrão de separação de dados parece ser mais simples do que realmente é. Seu código se torna mais sofisticado como resultado desse padrão e é necessária uma estrutura de autorização mais complicada.

Pode ser difícil para os desenvolvedores utilizar consistentemente o padrão KeyValuePair. Sabe-se que os desenvolvedores salvam seus valores como bytes32 antes de recuperar os valores originais usando a conversão de tipo. O modelo de dados se tornou mais sofisticado como resultado, aumentando a possibilidade de erros sutis. Essa prática levará a erros de desenvolvedores que não têm experiência com estruturas de dados sofisticadas.

Padrão de proxy baseado em delegações

O padrão de proxy baseado em chamada delegada é um padrão de design, frequentemente usado no desenvolvimento de contratos inteligentes. Envolve o uso do código de operação de chamada delegada para repassar uma chamada para outro contrato, enquanto ainda usa o contexto (por exemplo, o endereço do contrato de chamada e o saldo) do contrato de chamada. Isso permite que o contrato chamado (“o proxy” ) acesse e modifique o estado do contrato de chamada, mantendo a separação de preocupações entre os dois contratos.

Um caso de uso comum para o padrão de proxy baseado em chamada delegada é permitir atualizações de contrato sem alterar o endereço do contrato.

Usando um proxy baseado em chamada delegada, a lógica do contrato pode ser atualizada modificando o código do contrato de proxy, enquanto o contrato de chamada permanece inalterado.

Isso pode ser útil em situações em que o contrato de chamada possui inúmeras dependências ou em que não é prático atualizar o contrato de chamada diretamente.

No entanto, é importante observar que o padrão de proxy baseado em chamada delegada também pode introduzir riscos de segurança se não for implementado corretamente.

Por exemplo, se o contrato de proxy não for validado adequadamente ou se contiver vulnerabilidades, poderá comprometer a segurança do contrato de chamada. Como em qualquer padrão inteligente de design de contrato, é importante considerar cuidadosamente os riscos potenciais e tomar medidas para mitigá-los.


pragma solidity ^0.6.0;



// A interface do contrato que será atualizada.

interface Upgradable {

function doSomething() external;

}



// O contrato proxy delegado para chamar o contrato de implementação.



contract Proxy {

address internal implementation;



// O constructor define a implementação inicial.

constructor(address _implementation) public {

implementation = _implementation;

}



//Encaminha qualquer chamada de função para o contrato de implementação.

function() external payable {

(bool success, bytes memory data) = address(implementation).delegatecall(msg.data);

require(success, "Delegate call failed");

if (msg.sender.call{value: msg.value}(data)) {

revert();

}

}



//Atualiza para um novo contrato de implementação.

function upgrade(address _newImplementation) public {

implementation = _newImplementation;

}

}



// O contrato de implementação que o proxy delega.

contract ImplementationV1 is Upgradable {

function doSomething() external {

// O código de implementação vai aqui.

}

}

Enter fullscreen mode Exit fullscreen mode

Neste exemplo, o contrato Proxy é o contrato atualizável com o qual os usuários irão interagir. Tem uma única função, upgrade, que permite ao proprietário definir um novo contrato de implementação. Todas as outras chamadas de função são encaminhadas para o contrato de implementação usando o código de operação delegatecall.

O contrato ImplementationV1 é um exemplo de contrato de implementação conforme a interface Upgradable. Tem uma única função, doSomething, que pode ser chamada através do proxy. Se você deseja atualizar para uma nova implementação, pode implantar um novo contrato que também esteja conforme a interface Upgradable e uso da função upgrade no proxy para defini-lo como a nova implementação.

Aqui está abaixo um mapa mental mostrando a atualização




— — — — — —

| Atualizável |

— — — — — — -

|

— — — — — — — — — — — — — — — — 

| |

— — — — — — — — — — — — — — — — 

| Proxy | — — — - | Implementação | ou | Implementação |

— — — — — — — — — — — — — — — — 

| |

— — — — — — — — — — — — — — — — 

| Atualizar para nova versão | | Atualizar para nova versão |

— — — — — — — — — — — — — — — — 





Enter fullscreen mode Exit fullscreen mode

Estratégias de armazenamento de dados

Existem várias estratégias que podem ser usadas para armazenamento de dados em um contrato que usa o código de operação delegada:

  1. Armazenamento separado: Uma opção é usar o armazenamento separado para o contrato de chamada e o contrato delegado. Isso pode ser útil se os dois contratos tiverem estruturas de dados diferentes ou se for importante manter uma separação clara entre os dois contratos.

  2. Armazenamento compartilhado: Outra opção é usar o armazenamento compartilhado para o contrato de chamada e o contrato delegado. Isso pode ser alcançado usando um mapeamento ou uma matriz para armazenar dados compartilhados entre os dois contratos. Essa pode ser uma solução mais eficiente se os dois contratos tiverem estruturas de dados semelhantes ou se for necessário compartilhar dados com frequência.

  3. Armazenamento híbrido: Uma abordagem híbrida também é possível, onde alguns dados são armazenados separadamente e outros são compartilhados. Isso pode permitir um equilíbrio entre os benefícios do armazenamento separado e compartilhado, dependendo das necessidades específicas dos contratos.

É importante considerar cuidadosamente as trocas entre essas diferentes estratégias de armazenamento de dados e escolher a mais apropriada para o caso de uso específico. Os fatores a serem considerados podem incluir as estruturas de dados dos contratos, a frequência de acesso e modificação de dados e as implicações de segurança da estratégia de armazenamento escolhida.

Os riscos do padrão de proxy baseado em Delegatecall

O código de operação da chamada delegada pode introduzir vários riscos se não for usado com cuidado:

🚀 Riscos de segurança: O contrato delegado pode acessar e modificar o estado do contrato de chamada, o que pode comprometer potencialmente a segurança do contrato de chamada se o contrato delegado contiver vulnerabilidades ou não for validado adequadamente. É importante testar e auditar minuciosamente o contrato de chamada e o contrato delegado para garantir que eles sejam seguros.

🚀 Problemas de compatibilidade: O contrato delegado deve ser compatível com o contrato de chamada para funcionar corretamente. Se os dois contratos tiverem estruturas de dados incompatíveis ou usarem versões diferentes da mesma biblioteca, isso poderá levar a erros ou comportamento inesperado.

🚀 Complexidade: O uso do código de operação de chamada delegada pode aumentar a complexidade de um contrato, pois requer coordenação entre dois contratos separados. Isso pode dificultar a compreensão e manutenção do contrato e também aumentar o risco de erros ou bugs.

🚀 Perda de controle. Ao usar o código de operação de chamada delegada, o contrato de chamada está essencialmente renunciando ao controle do contrato delegado. Isso pode ser problemático se o contrato delegado não for confiável ou se se comportar inesperadamente.

No geral, é importante considerar cuidadosamente os riscos do uso do código de operação delegada e tomar medidas para mitigar esses riscos. Isso pode incluir testes e auditorias completas do contrato de chamada e do contrato delegado, além de implementar defesas apropriadas para proteger contra vulnerabilidades e outros riscos.

Resumo:

Contratos inteligentes atualizáveis são um tipo de contrato inteligente que pode ser modificado ou atualizado após a implantação na blockchain. Embora esse possa ser um recurso útil, também existem algumas armadilhas em potencial ao usar contratos inteligentes atualizáveis:

  1. Problemas de compatibilidade: A atualização de um contrato inteligente pode exigir alterações em seu código ou a adição de novas funções. Essas alterações podem não ser compatíveis com aplicativos ou sistemas existentes que estão usando o contrato, o que pode levar a interrupções ou erros.

  2. Vulnerabilidades de segurança: Modificar um contrato inteligente também pode introduzir novas vulnerabilidades ou expor as existentes. É importante testar e auditar minuciosamente um contrato atualizado para garantir que ele seja seguro.

  3. Perda de confiança: A atualização de um contrato inteligente pode ser percebida como uma alteração nos termos do acordo que o contrato representa. Isso pode levar a uma perda de confiança no contrato ou nas partes envolvidas, o que pode ter consequências negativas.

  4. Complexidade: Gerenciar e coordenar as atualizações de um contrato inteligente pode ser complexo e demorado. Pode ser necessário ter um processo claro e bem definido para garantir que as atualizações sejam implementadas de maneira suave e eficiente.

No geral, é importante considerar cuidadosamente as possíveis armadilhas do uso de contratos inteligentes atualizáveis e tomar medidas para mitigar esses riscos.

Lidando com a segurança da web3!!! Conecte-se conosco!!!

BlockAudit:- Por que nós??

A BlockAudit possui recursos e conhecimentos para criar soluções de segurança cibernética que economizam milhões de dólares.

Linkedin | Site | Twitter


Este artigo foi escrito por  BlockAudit e traduzido por Adriano P. de Araujo. O original em inglês pode ser encontrado aqui.

Top comments (0)