> For the complete documentation index, see [llms.txt](https://lunes-labs.gitbook.io/dao-lunes-labs-pt/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lunes-labs.gitbook.io/dao-lunes-labs-pt/developers/para-desenvolvedores/smart-contract-ink-4.x/fundamentos/contratos-atualizaveis.md).

# Contratos Atualizáveis

Embora os contratos inteligentes sejam projetados para serem imutáveis, muitas vezes é necessário realizar uma atualização de um contrato inteligente.&#x20;

O desenvolvedor pode precisar corrigir um bug crítico ou introduzir um novo recurso.&#x20;

Para esse tipo de cenário, o ink! possui diferentes estratégias de atualização.

* [Encaminhamento por Proxy](https://use.ink/basics/upgradeable-contracts#proxy-forwarding)
  * [Propriedades](https://use.ink/basics/upgradeable-contracts#properties)
* [Substituindo o Código do Contrato com](https://use.ink/basics/upgradeable-contracts/#replacing-contract-code-with-set_code_hash) [`set_code_hash()`](https://use.ink/basics/upgradeable-contracts#replacing-contract-code-with-set_code_hash)
  * [Propriedades](https://use.ink/basics/upgradeable-contracts#properties-1)
  * [Compatibilidade de Armazenamento](https://use.ink/basics/upgradeable-contracts#storage-compatibility)
  * [Uma pequena observação sobre o determinismo dos endereços de contrato](https://use.ink/basics/upgradeable-contracts#a-little-note-on-the-determinism-of-contract-addresses)
* [Exemplos](https://use.ink/basics/upgradeable-contracts#examples)

### Encaminhamento por Proxy <a href="#proxy-forwarding" id="proxy-forwarding"></a>

Este método depende da capacidade dos contratos de encaminhar chamadas para outros contratos.

#### Propiedades[​](https://use.ink/basics/upgradeable-contracts#properties) <a href="#properties" id="properties"></a>

* Encaminha qualquer chamada que não corresponda a um seletor próprio para outro contrato.
* O outro contrato precisa estar implantado na cadeia on-chain.
* O estado é armazenado no armazenamento do contrato para o qual as chamadas são encaminhadas.

```rust
User ---- tx ---> Proxy ----------> Implementation_v0
                     |
                      ------------> Implementation_v1
                     |
                      ------------> Implementation_v2
```

Nosso contrato de proxy terá esses 2 campos de armazenamento:

```rust
#[ink(storage)]
pub struct Proxy {
    /// The `AccountId` of a contract where any call that does not match a
    /// selector of this contract is forwarded to.
    forward_to: AccountId,
    /// The `AccountId` of a privileged account that can update the
    /// forwarding address. This address is set to the account that
    /// instantiated this contract.
    admin: AccountId,
}
```

Então, precisamos de uma maneira de alterar o endereço de um contrato para o qual encaminhamos as chamadas e o seletor de mensagem real para encaminhar a chamada:

```rust
impl Proxy {
    /// Changes the `AccountId` of the contract where any call that does
    /// not match a selector of this contract is forwarded to.
    #[ink(message)]
    pub fn change_forward_address(&mut self, new_address: AccountId) {
        assert_eq!(
            self.env().caller(),
            self.admin,
            "caller {:?} does not have sufficient permissions, only {:?} does",
            self.env().caller(),
            self.admin,
        );
        self.forward_to = new_address;
    }

    /// Fallback message for a contract call that doesn't match any
    /// of the other message selectors.
    ///
    /// # Note:
    ///
    /// - We allow payable messages here and would forward any optionally supplied
    ///   value as well.
    /// - If the self receiver were `forward(&mut self)` here, this would not
    ///   have any effect whatsoever on the contract we forward to.
    #[ink(message, payable, selector = _)]
    pub fn forward(&self) -> u32 {
        ink::env::call::build_call::<ink::env::DefaultEnvironment>()
            .call_type(
                Call::new()
                    .callee(self.forward_to)
                    .transferred_value(self.env().transferred_value())
                    .gas_limit(0),
            )
            .call_flags(
                ink::env::CallFlags::default()
                    .set_forward_input(true)
                    .set_tail_call(true),
            )
            .fire()
            .unwrap_or_else(|err| {
                panic!(
                    "cross-contract call to {:?} failed due to {:?}",
                    self.forward_to, err
                )
            });
        unreachable!(
            "the forwarded call will never return since `tail_call` was set"
        );
    }
}
```

<mark style="color:purple;">DICA: Dê uma olhada no padrão de seletor no atributo macro: ao declarar</mark> <mark style="color:purple;"></mark><mark style="color:purple;">`selector = _`</mark><mark style="color:purple;">, especificamos que todas as outras mensagens devem ser tratadas por este seletor de mensagem.</mark>

Usando esse padrão, você pode introduzir outras mensagens em seu contrato de proxy. Todas as mensagens que não forem correspondidas no contrato de proxy serão encaminhadas para o endereço de contrato especificado.

### Substituindo o Código do Contrato por `set_code_hash()`[​](https://use.ink/basics/upgradeable-contracts#replacing-contract-code-with-set_code_hash) <a href="#replacing-contract-code-with-set_code_hash" id="replacing-contract-code-with-set_code_hash"></a>

Seguindo a filosofia de atualização da [runtime da Lunes](https://docs.substrate.io/maintain/runtime-upgrades/), o ink! também oferece uma maneira fácil de atualizar o código do seu contrato por meio da função especial [`set_code_hash()`](https://paritytech.github.io/ink/ink_env/fn.set_code_hash.html).

Seguindo a filosofia de atualização de [tempo de execução do Substrate](https://docs.substrate.io/maintain/runtime-upgrades/) que é a mesma da Lunes, o ink! também oferece uma maneira fácil de atualizar o código do seu contrato por meio da função especial [`set_code_hash()`](https://paritytech.github.io/ink/ink_env/fn.set_code_hash.html).

#### Propriedades[​](https://use.ink/basics/upgradeable-contracts#properties-1) <a href="#properties-1" id="properties-1"></a>

* Atualiza o código do contrato usando `set_code_hash()`. Isso efetivamente substitui o código que é executado para o endereço do contrato.
* O outro contrato precisa estar implantado na cadeia on-chain.
* O estado é armazenado no armazenamento do contrato originalmente instanciado.

Basta adicionar a seguinte função ao contrato que você deseja atualizar no futuro.

```rust
/// Modifies the code which is used to execute calls to this contract address (`AccountId`).
///
/// We use this to upgrade the contract logic. We don't do any authorization here, any caller
/// can execute this method. In a production contract you would do some authorization here.
#[ink(message)]
pub fn set_code(&mut self, code_hash: [u8; 32]) {
    ink::env::set_code_hash(&code_hash).unwrap_or_else(|err| {
        panic!(
            "Failed to `set_code_hash` to {:?} due to {:?}",
            code_hash, err
        )
    });
    ink::env::debug_println!("Switched code hash to {:?}.", code_hash);
}
```

#### Compatibilidade de Armazenamento[​](https://use.ink/basics/upgradeable-contracts#storage-compatibility) <a href="#storage-compatibility" id="storage-compatibility"></a>

É responsabilidade do desenvolvedor garantir que o armazenamento do novo contrato seja compatível com o armazenamento do contrato que está sendo substituído.

<mark style="color:purple;">CUIDADO: Você não deve alterar a ordem em que as variáveis de estado do contrato são declaradas, nem seu tipo!</mark>&#x20;

<mark style="color:purple;">Violar essa restrição não impedirá uma compilação bem-sucedida, mas resultará</mark> <mark style="color:purple;"></mark><mark style="color:purple;">**na mistura de valores**</mark> <mark style="color:purple;"></mark><mark style="color:purple;">ou</mark> <mark style="color:purple;"></mark><mark style="color:purple;">**na falha ao ler o armazenamento corretamente**</mark><mark style="color:purple;">. Isso pode resultar em erros graves na aplicação que utiliza o contrato.</mark>

Se o armazenamento do seu contrato parece assim:

```rust
#[ink(storage)]
pub struct YourContract {
    x: u32,
    y: bool,
}
```

Os procedimentos listados abaixo tornarão o contrato **inválido**

Alterando a ordem das variáveis:

```rust
#[ink(storage)]
pub struct YourContract {
    y: bool,
    x: u32,
}
```

Removendo uma variável existente:

```rust
#[ink(storage)]
pub struct YourContract {
    x: u32,
}
```

Alterando o tipo de uma variável:

```rust
#[ink(storage)]
pub struct YourContract {
    x: u64,
    y: bool,
}
```

Introduzindo uma nova variável antes de qualquer uma das existentes:

```rust
#[ink(storage)]
pub struct YourContract {
    z: Vec<u32>,
    x: u32,
    y: bool,
}
```

#### Uma pequena observação sobre a determinismo dos endereços de contrato.[​](https://use.ink/basics/upgradeable-contracts#a-little-note-on-the-determinism-of-contract-addresses) <a href="#a-little-note-on-the-determinism-of-contract-addresses" id="a-little-note-on-the-determinism-of-contract-addresses"></a>

<mark style="color:purple;">NOTA: Se o seu contrato utiliza essa abordagem, não é mais válido assumir que um endereço de contrato identifica um hash de código específico. Consulte a issue para obter mais detalhes.</mark>

### Exemplos[​](https://use.ink/basics/upgradeable-contracts#examples) <a href="#examples" id="examples"></a>

Exemplos de contratos atualizáveis podem ser encontrados no [repositório do ink!](https://github.com/paritytech/ink-examples/tree/main/upgradeable-contracts).
