Aprenda como atualizar um palete do Substrate sem bifurcar a blockchain
Introdução
A descentralização de blockchains tem vantagens e desvantagens. Uma das principais vantagens é que não existe uma única unidade que tenha poder completo sobre um sistema. Por outro lado, uma desvantagem é que no ambiente sem controle centralizado, a atualização é difícil devido à necessidade de coordenar vários nós ao mesmo tempo. Uma das soluções mais conhecidas de atualização de blockchains é o chamado “hard fork” (bifurcação rígida), porém este possui muitos vetores potenciais de ataque e é difícil de coordenar.
A solução mais recente para atualizar sistemas descentralizados com base na estrutura Substrate é chamada de runtime-upgrade
. A solução funciona sem problemas e neste tutorial, mostrarei como você pode atualizar facilmente sua cadeia baseada em Substrate. Examinaremos como a adaptabilidade é implementada na estrutura do Substrate.
Pré-requisitos
Para seguir este tutorial com sucesso, você deve ter um conhecimento básico sobre a linguagem de programação Rust e o framework Substrate da Polkadot.
Começando
Durante o tutorial, vamos progredir através destas etapas:
- Compile a mais simples blockchain baseada em Substrate;
- Execute a cadeia do Substrate localmente (em seu próprio hardware);
- Adicione um novo recurso ao tempo de execução;
- Crie um arquivo WebAssembly (WASM);
- Verifique a atualização verificando a versão.
A atualização da função de transição de estado de tempo de execução consiste nas seguintes etapas:
- Acresça (aumente) o
spec_version
- Compile o arquivo
WASM: WASM_TARGET_DIRECTORY="$(pwd)" cargo build
- Use o comando
sudo
para iniciar o tempo de execução
Compilando uma simples blockchain do Substrate
Veja a ramificação (branch) master de https://github.com/TomaszWaszczyk/substrate-runtime-upgrade-tutorial, e então execute o comando make init
e após cerca de 10 minutos (depende do desempenho da sua máquina) você deverá ver algo como:
Compiling sc-finality-grandpa v0.8.0
Compiling rocksdb v0.15.0
Compiling kvdb-rocksdb v0.9.1
Compiling sc-client-db v0.8.0
Compiling sc-service v0.8.0
Compiling sc-cli v0.8.0
Compiling frame-benchmarking-cli v2.0.0
Finished dev [unoptimized + debuginfo] target(s) in 13m 01s
Nota: Se você deseja construir uma versão otimizada do projeto, execute cargo build --release
Execute o nó Substrate localmente
Use o comando make run
:
Running `target/debug/node-template --dev -lruntime=debug`
Sep 29 18:18:09.106 WARN Running in --dev mode, RPC CORS has been disabled.
Sep 29 18:18:09.106 INFO Substrate Node
Sep 29 18:18:09.106 INFO ✌️ version 2.0.0-73d7748-x86_64-linux-gnu
Sep 29 18:18:09.106 INFO ❤️ by Substrate DevHub <https://github.com/substrate-developer-hub>, 2017-2021
Sep 29 18:18:09.106 INFO 📋 Chain specification: Development
Sep 29 18:18:09.106 INFO 🏷 Node name: frantic-insect-7496
Sep 29 18:18:09.106 INFO 👤 Role: AUTHORITY
Sep 29 18:18:09.107 INFO 💾 Database: RocksDb at /home/tomek/.local/share/node-template/chains/dev/db
Sep 29 18:18:09.107 INFO ⛓ Native runtime: node-template-1 (node-template-1.tx1.au1)
Sep 29 18:18:10.070 INFO 🔨 Initializing Genesis block/state (state: 0x0f2a...c2cc, header-hash: 0x1e1d...f017)
Sep 29 18:18:10.073 INFO 👴 Loading GRANDPA authority set from genesis on what appears to be first startup.
Sep 29 18:18:10.294 INFO ⏱ Loaded block-time = 2000 milliseconds from genesis on first-launch
Sep 29 18:18:10.295 WARN Using default protocol ID "sup" because none is configured in the chain specs
Sep 29 18:18:10.296 INFO 🏷 Local node identity is: 12D3KooWNo1348XGxpiA9uFJn4GJdptp7NcX72pFXsGZXghPKLYa (legacy representation: 12D3KooWNo1348XGxpiA9uFJn4GJdptp7NcX72pFXsGZXghPKLYa)
Sep 29 18:18:10.618 INFO 📦 Highest known block at #0
Sep 29 18:18:10.620 INFO 〽️ Prometheus server started at 127.0.0.1:9615
Sep 29 18:18:10.624 INFO Listening for new connections on 127.0.0.1:9944.
Sep 29 18:18:12.249 INFO 🙌 Starting consensus session on top of parent 0x1e1dd820c46a22dbd297afd5a62e73511208bafe64c6dc9e6a171562c443f017
Sep 29 18:18:12.397 INFO 🎁 Prepared block for proposing at 1 [hash: 0x3b7c2d4f453358a70095cc0ad55a5f157a5be3d145c42213ea88c419b48966bf; parent_hash: 0x1e1d...f017; extrinsics (1): [0xff0f...0d06]]
Sep 29 18:18:12.515 INFO 🔖 Pre-sealed block for proposal at 1. Hash now 0xc61a8f6ea035c0fd2e8acef986a60ec92abbaaa1f30c4781603d4ec83591b216, previously 0x3b7c2d4f453358a70095cc0ad55a5f157a5be3d145c42213ea88c419b48966bf.
Sep 29 18:18:12.517 INFO ✨ Imported #1 (0xc61a...b216)
Sep 29 18:18:14.123 INFO 🙌 Starting consensus session on top of parent 0xc61a8f6ea035c0fd2e8acef986a60ec92abbaaa1f30c4781603d4ec83591b216
Acesse o front-end do nó local no link: https://polkadot.js.org/apps/#/extrinsics?rpc=ws://127.0.0.1:9944
Podemos ver que o palete Kitties (gatinhos) possui apenas uma função create()
, que é a nossa função de transição de estado atual em tempo de execução. Para demonstrar como as blockchains baseadas em Substrate são adaptáveis, podemos adicionar um novo recurso - a função breed()
(raça).
Adicionando um recurso ao tempo de execução
Antes de fazer uma atualização, o spec_version
seria 1. Agora que estamos fazendo uma atualização, incrementamos o campo e então agora ele será 2, conforme mostrado abaixo:
pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("node-template"),
impl_name: create_runtime_str!("node-template"),
authoring_version: 1,
spec_version: 2, // incremented version
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
};
Nossa atualização adicionará uma nova função ao palete Kitties chamada breed
, aqui está a implementação:
/// Breed e kitties
#[weight = 1000]
pub fn breed(origin, kitty_id_1: u32, kitty_id_2: u32) {
let sender = ensure_signed(origin)?;
let kitty1 = Self::kitties(&sender, kitty_id_1).ok_or(Error::<T>::InvalidKittyId)?;
let kitty2 = Self::kitties(&sender, kitty_id_2).ok_or(Error::<T>::InvalidKittyId)?;
ensure!(kitty1.gender() != kitty2.gender(), Error::<T>::SameGender);
let kitty_id = Self::get_next_kitty_id()?;
let kitty1_dna = kitty1.0;
let kitty2_dna = kitty2.0;
let selector = Self::random_value(&sender);
let mut new_dna = [0u8; 16];
// Combine os pais e o seletor para criar um novo gatinho
for i in 0..kitty1_dna.len() {
new_dna[i] = combine_dna(kitty1_dna[i], kitty2_dna[i], selector[i]);
}
let new_kitty = Kitty(new_dna);
Kitties::<T>::insert(&sender, kitty_id, &new_kitty);
Self::deposit_event(RawEvent::KittyBred(sender, kitty_id, new_kitty));
}
Depois de adicionar a função breed
ao palete Kitties, precisamos construir o arquivo WASM.
Aqui está um link para toda a nova implementação: https://github.com/TomaszWaszczyk/substrate-runtime-upgrade-tutorial/blob/after-runtime-upgrade/pallets/kitties/src/lib.rs
Após realizar a atualização, esperamos que o palete Kitties contenha a nova função breed
sem a necessidade de reiniciar o nó Substrate em execução. Adaptabilidade real da blockchain!
Compilando o arquivo WASM de tempo de execução
Execute o comando de terminal WASM_TARGET_DIRECTORY="$(pwd)" cargo build
para compilar o arquivo WASM de tempo de execução.
Após uma compilação bem-sucedida, esperamos ter um novo arquivo no diretório atual:
Atualizando o tempo de execução
Temos um nó Substrate em execução com a versão 1 e queremos atualizar o tempo de execução para a versão 2. A prova de uma atualização bem-sucedida será nossa função recém-adicionada, breed
. Vamos verificar, usando o front-end.
Para realizar a atualização, vá para a guia Developer e selecione Sudo. Certifique-se de ter selecionado o palete system
e setCode(code)
, marque a opção file upload
e selecione o arquivo WASM recém-criado na etapa anterior: node_template_runtime.wasm
. Em seguida, marque a opção “with weight override” (substituição com peso) e no campo unchecked weight for this call (peso desmarcado para esta chamada) digite um valor como 100, por exemplo. Para confirmar a atualização, clique em Submit Sudo Unchecked (Enviar Sudo Desmarcado).
Após a atualização com sucesso, você deverá ver spec_version
atualizado e ter acesso à nossa nova função:
Na captura de tela acima, podemos ver o resultado de uma atualização bem-sucedida. Observe que spec_version
foi incrementado para 2 (onde diz "node-template/2").
Solução de problemas
Problema: Erros do Rust ao compilar
Você pode encontrar um erro durante a compilação, como o mostrado abaixo. Isso significa que você não tem a versão correta do Rust instalada.
Compiling prost-derive v0.6.1
error[E0034]: multiple applicable items in scope
--> /home/tomek/.cargo/registry/src/github.com-1ecc6299db9ec823/prost-derive-0.6.1/src/lib.rs:111:14
|
111 | .intersperse(quote!(|));
| ^^^^^^^^^^^ multiple `intersperse` found
|
= note: candidate #1 is defined in an impl of the trait `Iterator` for the type `Map<I, F>`
= note: candidate #2 is defined in an impl of the trait `Itertools` for the type `T`
help: disambiguate the associated function for candidate #1
|
107 ~ let tags = Iterator::intersperse(field
108 + .tags()
109 + .into_iter()
110 + .map(|tag| quote!(#tag)), {
111 + let mut _s = $crate::__private::TokenStream::new();
112 + $crate::quote_each_token!(_s $($tt)*);
...
help: disambiguate the associated function for candidate #2
|
107 ~ let tags = Itertools::intersperse(field
108 + .tags()
109 + .into_iter()
110 + .map(|tag| quote!(#tag)), {
111 + let mut _s = $crate::__private::TokenStream::new();
112 + $crate::quote_each_token!(_s $($tt)*);
...
For more information about this error, try `rustc --explain E0034`.
Compiling asn1_der_derive v0.1.2
error: could not compile `prost-derive` due to previous error
warning: build failed, waiting for other jobs to finish...
error: build failed
make: *** [Makefile:11: build-full] Error 101
Solução - configure e defina a versão padrão adequada da linguagem Rust em sua máquina
Você precisa instalar e definir como padrão a compilação noturna especificada do Rust: Linguagem Rust rustup update nightly-2020-08-23
- Instalação
rustup update nightly-2020-08-23
- Faça dela a versão padrão
rustup default nightly-2020-08-23-x86_64-unknown-linux-gnu
- Verificação da versão padrão
rustup show
e na saída você deve ver o seguinte:
active toolchain
----------------
nightly-2020-08-23-x86_64-unknown-linux-gnu (default)
rustc 1.47.0-nightly (663d2f5cd 2020-08-22)
Conclusão
Parabéns! Você já entendeu a importância de como a adaptabilidade é importante em blockchains descentralizadas e como o recurso é implementado no framework Substrate.
Durante a leitura do tutorial, você aprendeu o básico da linguagem Rust, como compilar uma cadeia baseada em Substrate e como gerar e enviar o arquivo wasm para fornecer novos recursos para a cadeia.
Sobre o autor
O tutorial original foi criado por Tomasz Waszczyk. Em caso de dúvidas, você pode entrar em contato com Tomasz no Fórum da Figment e no Github para obter ajuda ou esclarecer dúvidas relacionadas ao ecossistema Polkadot/Kusama e a este guia. Traduzido por Paulinho Giovannini.
Referências
Quando tiver concluído o tutorial, você estará pronto para aprender mais lendo o tutorial sobre atualização de tempo de execução sem bifurcação de Jimmy Chu.
Latest comments (0)