🇵🇹
DAO Lunes Labs - PT
  • 👋Seja Bem-vindo a DAO Lunes Labs
  • Overview
    • 🚪Introdução
    • 🚀Manifesto DAO Lunes Labs
    • 🍕Tokenomics
    • 👑Proposta de Valor
    • 🧑‍🚀Comunidade e Participação
    • 🗺️Roadmap
    • 💼Compromisso com Ética e Responsabilidade
    • 👾Programa de Bug Bounty: Lunes Security Initiative (LSI)
  • Developers
    • 💽Para Nodes
      • 🥾Instalar Node
        • 🏗️Rust toolchain
        • 🐧Linux
    • 🖥️Para Desenvolvedores
      • 📑Smart Contract Ink! 4.x
        • ✨Configuração
          • 📐Criando um projeto com ink!
          • 🖥️Compile Seu Contrato
          • ⛓️Executar um nó Lunes
          • ⬆️Implante seu contrato
          • 🔛Chame Seu Contrato
          • 🛠️Solução de problemas
        • 🪄Fundamentos
          • 👾Modelo de Contrato
          • 👨‍🚀Armazenando Valores
          • 🔭Lendo Valores do Armazenamento
          • 🦸‍♂️Alterando os Valores de Armazenamento
          • 🎡Eventos
          • 👨‍🔧Seletores
          • 🪶Definições de Trait
          • 🗣️Chamadas entre Contratos (Cross-Contract Calls)
          • 🦸Contratos Atualizáveis
          • 🤺Funções do Ambiente
          • 🏟️Tipos de Ambiente de Cadeia
          • 💠Metadados
          • 🧪Testes de Contrato
          • 🕵️‍♂️Depuração de Contratos
          • 🔬Verificação de Contrato
        • 🎙️Macros e Atributos
          • 📇#[ink::contract]
          • 👽#[ink(anonymous)]
          • 👷#[ink(constructor)]
          • 📏#[ink(default)]
          • 🎢#[ink(event)]
          • 🛩️#[ink(impl)]
          • 📧#[ink(message)]
          • 👨‍💼#[ink(namespace = "…")]
          • 💸#[ink(payable)]
          • ⚡#[ink(selector = S:u32)]
          • 💽#[ink(storage)]
          • 💣#[ink(topic)]
          • ⛓️#[ink::chain_extension]
        • 💽Storege & Data Structires
          • Working with Mapping
          • Storage Layout
          • Custom Data Structures
          • Metadata Format
        • 👾Frontend Development
          • Getting Started
          • Connect Wallet
          • Hooks
            • All Hooks
            • Contracts
              • useCall
              • useCallSubscription
              • useContract
              • useDryRun
              • useEventSubscription
              • useEvents
              • useTx
              • useTxPaymentInfo
            • Wallets
              • useWallet
              • useAllWallets
              • useInstalledWallets
              • useUninstalledWallets
            • API
              • useApi
              • useBalance
              • useBlockHeader
          • Configuration
          • useink / core
            • Contracts
              • Call
              • decodeCallResult
              • decodeError
              • getRegistryError
              • toAbiMessage
          • useink / chains
            • Getting Started
            • Chain Configurations
            • ChainId
          • useink / notifications
            • Getting Started
            • Configuration
            • useNotifications
            • toNotificationLevel
          • useink / utils
            • Getting Started
            • Pick Helpers
            • tx Helpers
            • Types
        • 💡Examples
          • 📔Smart Contracts
          • 📱Dapps
        • 🛠️Tools
          • 🖌️OpenBrush
      • 📒Smart Contract - EVM
        • Create ERC-20 Ink Token!
      • 💰Desenvolvendo uma Wallet Lunes
        • 👾Transações de Tokens PSP22
    • 🎨Para Designers
      • 🖌️Brand Lunes
Powered by GitBook
On this page
  • Encaminhamento por Proxy
  • Substituindo o Código do Contrato por set_code_hash()​
  • Exemplos​

Was this helpful?

  1. Developers
  2. Para Desenvolvedores
  3. Smart Contract Ink! 4.x
  4. Fundamentos

Contratos Atualizáveis

Last updated 1 year ago

Was this helpful?

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

O desenvolvedor pode precisar corrigir um bug crítico ou introduzir um novo recurso.

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

Encaminhamento por Proxy

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

Propiedades

  • 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.

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

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

#[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:

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"
        );
    }
}

DICA: Dê uma olhada no padrão de seletor no atributo macro: ao declarar selector = _, especificamos que todas as outras mensagens devem ser tratadas por este seletor de mensagem.

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.

  • 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.

/// 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);
}

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

CUIDADO: Você não deve alterar a ordem em que as variáveis de estado do contrato são declaradas, nem seu tipo!

Violar essa restrição não impedirá uma compilação bem-sucedida, mas resultará na mistura de valores ou na falha ao ler o armazenamento corretamente. Isso pode resultar em erros graves na aplicação que utiliza o contrato.

Se o armazenamento do seu contrato parece assim:

#[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:

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

Removendo uma variável existente:

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

Alterando o tipo de uma variável:

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

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

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

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.

Substituindo o Código do Contrato por set_code_hash()

Seguindo a filosofia de atualização da , o ink! também oferece uma maneira fácil de atualizar o código do seu contrato por meio da função especial .

Seguindo a filosofia de atualização de 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 .

Propriedades

Compatibilidade de Armazenamento

Uma pequena observação sobre a determinismo dos endereços de contrato.

Exemplos

Exemplos de contratos atualizáveis podem ser encontrados no .

🖥️
📑
🪄
🦸
Encaminhamento por Proxy
Propriedades
Substituindo o Código do Contrato com
set_code_hash()
Propriedades
Compatibilidade de Armazenamento
Uma pequena observação sobre o determinismo dos endereços de contrato
Exemplos
​
​
runtime da Lunes
set_code_hash()
tempo de execução do Substrate
set_code_hash()
​
​
​
​
repositório do ink!