Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust State Machine: translation section 3 #130

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions Rust_State_Machine/pt-BR/Section_3/Lesson_1_Generic_Types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
Antes de prosseguir, verifique se sua resposta corresponde à [solução da etapa anterior aqui](https://gist.github.com/nomadbitcoin/fe73ad648ad4cd64c782fdc85ceb5791).

Fantástico! Agora você entende a importância do Estado de Gênesis e está pronto para dar os primeiros passos em seu blockchain!

# Tipos Genéricos e Configuráveis

[Youtube](https://youtu.be/uXEoRoeoTg8?si=NnhqrqECI2N947pz)

Nesta seção, vamos aproveitar todo o poder do Rust para criar um Runtime genérico e configurável.

Não haverá mudanças lógicas reais nos próximos passos.

Em vez disso, vamos gradualmente abstrair os tipos concretos definidos em nossos Pallets e, em vez disso, estruturar nosso código para lidar puramente com tipos genéricos.

No final da seção, você terá um projeto cuja estrutura espelha exatamente o que é encontrado no Polkadot SDK e entenderá como tudo funciona.

# Usando Tipos Nomeados

Até agora, estivemos codificando tipos brutos diretamente em nossas structs e definições de funções.

Já existem exemplos onde isso pode ser confuso, por exemplo, se você vê uma função aceitar um parâmetro `u32`, é um `blocknumber` ou um `nonce`?

Para tornar nosso código mais claro, vamos extrair todos os nossos tipos brutos e definir tipos nomeados personalizados para nossas structs e funções.

Nos Pallets de Saldos e Sistema, precisamos definir os seguintes tipos:

1. `type AccountId = String;`
2. `type Balance = u128;`
3. `type Nonce = u32;`
4. `type BlockNumber = u32;`

Observe que extrair esses tipos para definições de tipos comuns também nos permite atualizar os tipos mais facilmente, se assim escolhermos.

À medida que avançamos neste tutorial, mostraremos como podemos tornar essas definições de tipos ainda mais flexíveis e personalizáveis no contexto da construção de um SDK de blockchain para desenvolvedores como você.

# Exercício:

### Criar Tipos Personalizados

Siga os `TODO`s no template para adicionar essas definições de tipo a cada um dos seus Pallets e atualize todas as suas structs e funções para usar esses tipos.

No `balances.rs`:
```rust
use std::collections::BTreeMap;

/*
TODO: Defina os tipos comuns usados ​​nesta pallet:
- `AccountId`
- `Balance`

Em seguida, atualize esta paleta para usar esses tipos comuns.
*/

/// Este é o Módulo de Saldos.
/// É um módulo simples que monitora quanto saldo cada conta tem nesta máquina de estado.
#[derive(Debug)]
pub struct Pallet {
// Um mapeamento simples de armazenamento de contas (`String`) para seus saldos (`u128`).
balances: BTreeMap<String, u128>,
}
```
No `system.rs`:
```rust
use std::collections::BTreeMap;

/*
TODO: Defina os tipos comuns usados ​​nesta pallet:
- `AccountId`
- `BlockNumber`
- `Nonce`

Em seguida, atualize esta paleta para usar esses tipos comuns.
*/

/// Este é o Pallet do Sistema.
/// Ele lida com o estado de baixo nível necessário para seu blockchain.
#[derive(Debug)]
pub struct Pallet {
/// O número do bloco atual.
block_number: u32,
/// Um ​​mapa de uma conta para seu nonce.
nonce: BTreeMap<String, u32>,
}
```
72 changes: 72 additions & 0 deletions Rust_State_Machine/pt-BR/Section_3/Lesson_2_Num_Crate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
Você pode encontrar a [solução para a etapa anterior aqui](https://gist.github.com/nomadbitcoin/2cf138e17e3f8a6c01f2a862af822d14).

# Importando o Crate Num

[Youtube](https://youtu.be/FWCqR0ijnck?si=YlFCz6D6ivTAxVUk)

Rust é projetado para ser muito leve e fornece muito pouco pronto para uso.

Dentro do ecossistema, muitas funções e recursos que você poderia esperar ser incluídos no Rust `std` ou `core` são na verdade delegados para pequenos crates bem conhecidos e amplamente utilizados.

Para nosso próximo passo, queremos acessar traits para operações numéricas básicas como:

- `CheckedAdd` - Um tipo que suporta `checked_add`
- `CheckedSub` - Um tipo que suporta `checked_sub`
- `Zero` - Um tipo que pode retornar o valor zero ao chamar `zero()`
- `One` - Um tipo que pode retornar o valor um ao chamar `one()`

Para acessar essas traits, precisaremos importar um novo crate em nosso projeto.

## Cargo.toml

Quando inicializamos nosso projeto, um arquivo `Cargo.toml` foi gerado para nós.

Como mencionado antes, é muito semelhante a um arquivo `package.json` que você esperaria encontrar em um projeto Node.js.

Já no seu `Cargo.toml` estão metadados como o `name` do seu projeto a `version` do crate que você está construindo e a `edition` do Rust que você está usando.

O que você pode ver é que você também pode adicionar `dependencies` ao seu crate, o que permitirá que você use outros crates e bibliotecas externas em seu projeto.

Você pode adicionar a dependência manualmente editando seu arquivo `Cargo.toml` ou pode executar `cargo add num`.

## Crates.io

De onde vem este crate?

A comunidade Rust tem um grande registro de crates disponíveis no [crates.io](https://crates.io/). Quando você importa um crate, ele usará `crates.io` por padrão.

Você também pode importar crates diretamente do GitHub especificando o repositório onde o código-fonte pode ser encontrado.

Isso ficaria assim:

```toml
[dependencies]
pallet-balances = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" }
```

## Adicione o Crate Num ao Seu Projeto

Este passo é curto e simples.

Execute `cargo add num` no diretório do seu projeto e certifique-se de que seu projeto compile depois disso.

Você deve ver algo como:

```bash
➜ rust-state-machine git:(master) ✗ cargo add num
Updating crates.io index
Adding num v0.4.1 to dependencies.
Features:
+ std
- alloc
- libm
- num-bigint
- rand
- serde
Updating crates.io index
➜ rust-state-machine git:(master) ✗ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/rust-state-machine`
```

Agora, você adicionou com sucesso o crate `num` ao seu projeto e está pronto para usá-lo em suas próximas implementações.
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
# Tornando o Pallet de Saldos Genérico

[Youtube](https://youtu.be/Yq_WZJrDVhk?si=hdJbSEHav_zbJiTg)

Nosso objetivo nas próximas etapas será tornar nosso runtime mais genérico e configurável em relação aos tipos que usamos em nossos Pallets.

## Por que Genérico?

A flexibilidade de um runtime genérico significa que podemos escrever código que funcione para várias configurações e tipos diferentes.

Por exemplo, até agora, usamos `&'static str` para representar as contas dos usuários. Isso obviamente não é a coisa certa a fazer, mas é fácil de implementar para um tutorial básico de blockchain como este.

O que você precisaria mudar para usar chaves públicas criptográficas mais tradicionais?

Bem, atualmente há definições do tipo de conta tanto no Pallet de Saldos quanto no Pallet de Sistema. Imagine se você tivesse muitos mais Pallets também! Esse tipo de refatoração poderia ser muito difícil, mas totalmente evitado se usássemos tipos genéricos desde o início.

Na verdade, a vantagem dos tipos genéricos não será super evidente neste tutorial, mas ao construir um SDK de blockchain como o Substrate, esse tipo de flexibilidade permitirá que os desenvolvedores do ecossistema alcancem seu potencial máximo.

Por exemplo, equipes usaram o Substrate para construir blockchains totalmente compatíveis com Ethereum, enquanto outras equipes experimentaram primitivos criptográficos de ponta. Esse framework genérico permite que ambas as equipes sejam bem-sucedidas.

## Tipos Genéricos

Você já foi ligeiramente exposto a tipos genéricos com o tipo `Result`. Lembre-se de que esse tipo é flexível para permitir que você configure qual tipo é retornado quando há `Ok` ou `Err`.

Se quisermos tornar nosso `Pallet` genérico, ele pareceria algo assim:

```rust
pub struct Pallet<AccountId, Balance> {
balances: BTreeMap<AccountId, Balance>,
}
```

E implementar funções em `Pallet` pareceria assim:

```rust
impl<AccountId, Balance> Pallet<AccountId, Balance> {
// funções que usam esses tipos
}
```

Nesse caso, não definimos o que o tipo `AccountId` e `Balance` são concretamente, apenas que armazenaremos um `BTreeMap` onde o tipo `AccountId` é uma chave e o tipo `Balance` é um valor.

### Restrições de Traits

O tipo genérico `Result` é extremamente flexível porque não há restrições sobre o que o tipo `Ok` ou `Err` deve ser. Qualquer tipo funcionará para essa situação.

No entanto, nossos Pallets não são tão flexíveis. O tipo `Balance` não pode ser literalmente qualquer tipo. Porque temos funções como `fn transfer`, devemos exigir que o tipo `Balance` pelo menos tenha acesso à função `checked_sub`, `checked_add` e tenha alguma representação de `zero`.

É aqui que o crate `num` será útil. Do crate `num`, você pode importar traits que definem tipos que expõem essas funções:

```rust
use num::traits::{CheckedAdd, CheckedSub, Zero};
```

Então, onde aplicável, você precisa restringir seus tipos genéricos para ter essas traits.

Isso parecerá assim:

```rust
impl<AccountId, Balance> Pallet<AccountId, Balance>
where
AccountId: Ord,
Balance: Zero + CheckedSub + CheckedAdd + Copy,
{
// functions which use these types and have access to the traits specified
}
```

Você notará outros tipos como `Copy` e `Ord` que foram adicionados. Essas restrições vêm do uso de estruturas como o `BTreeMap`, que requer que o tipo de chave seja "ordenável".

Você pode realmente tentar compilar seu código sem essas restrições de tipo, e o compilador lhe dirá quais traits você está faltando e o que precisa incluir.

### Instanciando um Tipo Genérico

A peça final do quebra-cabeça é instanciar nossos tipos genéricos.

Anteriormente, poderíamos simplesmente escrever:

```rust
let mut balances = super::Pallet::new();
```

Mas agora que `Pallet` é genérico, precisamos definir concretamente esses tipos ao instanciá-lo.

Essa sintaxe parece assim:

```rust
let mut balances = super::Pallet::<&'static str, u128>::new();
```

Você notará que agora os tipos são definidos onde quer que a `struct Pallet` genérica esteja sendo instanciada. Isso significa que você pode extrair os tipos de seus Pallets e movê-los para o Runtime.

# Exercícios:

### Torne-se Genérico!

É hora de tornar seu pallet de saldos genérico.

1. Siga os `TODO`s no arquivo `balances.rs` para tornar `Pallet` genérico.
2. Mova as definições de tipo para `AccountId` e `Balance` para o seu `main.rs`.
3. Atualize sua `struct Runtime` para usar esses tipos ao definir o `balances::Pallet`.

Para ser honesto, este é um dos lugares onde os desenvolvedores mais frequentemente têm problemas ao aprender Rust, por isso há tanta ênfase em ensiná-lo e fazer você aprender fazendo esses passos sozinho.

Não tenha medo nesta etapa de espiar a solução se ficar preso, mas tente aprender os padrões de uso de tipos genéricos e o que toda a sintaxe significa em termos do que o compilador está tentando garantir sobre a segurança dos tipos.

No `balances.rs`:

```rust
/* TODO: Você pode precisar importar algumas coisas para este passo. */
use std::collections::BTreeMap;
use num::traits::{CheckedAdd, CheckedSub, Zero};

/*
TODO:
Atualize a struct `Pallet` para ser genérica em relação aos tipos `AccountId` e `Balance`.

Você não precisará das definições de tipo abaixo depois de concluir.
Os tipos agora serão definidos em `main.rs`. Veja os TODOs lá.
*/

/// Este é o Módulo de Saldos.
/// É um módulo simples que mantém o controle de quanto saldo cada conta possui nesta máquina de estados.
#[derive(Debug)]
pub struct Pallet {
// Um armazenamento simples mapeando contas para seus saldos.
balances: BTreeMap<AccountId, Balance>,
}

/*
TODO:
Os tipos genéricos precisam satisfazer certas características para serem usados ​​nas funções abaixo.
- AccountId: Ord
- Balance: Zero + CheckedSub + CheckedAdd + Copy

Você pode descobrir essas características deixando o compilador dizer o que está faltando.

NOTA: Pode ser necessário ajustar algumas das funções abaixo para satisfazer o verificador de empréstimo.
*/

/// ...código anterior.

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn init_balances() {
/*
TODO:
Ao criar uma instância de `Pallet`, você deve definir explicitamente os tipos que usa.
*/
let mut balances = super::Pallet::new();

/// ...código anterior.
}

#[test]
fn transfer_balance() {
/*
TODO:
Ao criar uma instância de `Pallet`, você deve definir explicitamente os tipos que usa.
*/
let mut balances = super::Pallet::new();

/// ...código anterior.
}
}
```

No `main.rs`:

```rust
mod balances;
mod system;

// Estes são os tipos concretos que usaremos em nossa máquina de estados simples.
// Os módulos são configurados diretamente para esses tipos e satisfazem todos os nossos
// requisitos de característica.
mod types {
/*
TODO: Mova suas definições de tipo para `AccountId` e `Balance` aqui.
*/
}

// Este é o nosso Runtime principal.
// Acumula todos os diferentes pallets que queremos utilizar.
#[derive(Debug)]
pub struct Runtime {
system: system::Pallet,
/* TODO: Use suas definições de tipo para seus novos `balances::Pallet` genéricos. */
balances: balances::Pallet,
}
```

Tornar o Balances Pallet genérico é uma habilidade crucial para a criação de soluções blockchain flexíveis e escaláveis. Ótimo trabalho ao concluir esta lição! 🌟
Poste uma captura de tela em [#progress](https://discord.com/channels/898706705779687435/980906289968345128) mostrando seu runtime com o novo Balances Pallet genérico em ação. É melhor ainda não estar usando `&'static str`!
Loading
Loading