WEB3DEV

Cover image for Como construir uma blockchain do zero em Rust
Jhonattan Farias
Jhonattan Farias

Posted on • Atualizado em

Como construir uma blockchain do zero em Rust

2021 foi um grande ano para criptomoedas, NFTs e aplicativos descentralizados (DAPPs), e 2022 será ainda maior. Blockchain é a tecnologia subjacente por trás de todas essas tecnologias.
A tecnologia Blockchain tem o potencial de mudar quase todos os aspectos de nossas vidas, desde o setor financeiro, viagens e mobilidade, infraestrutura, saúde, setor público, varejo, agricultura, mineração, educação, comunicação, entretenimento e muito mais.

Todas as pessoas inteligentes que admiro no mundo, e aquelas que quase temo, estão focadas nesse conceito de criptomoedas por um motivo. Eles entendem que esta é a força motriz da quarta revolução industrial: motor a vapor, eletricidade, então o microchip – blockchain e criptomoedas é a quarta. - Brock Pierce

Essa imagem representa uma cadeia de blocos

O que é uma blockchain?

Uma blockchain é um registro descentralizado de transações em uma rede ponto-a-ponto, você também pode pensar em uma blockchain como um banco de dados descentralizado que é imutável. Uma blockchain pode ser dividida fundamentalmente em vários componentes, por exemplo, nó, transação, bloco, cadeia e protocolo de consenso (proof of work, proof of stake, proof of history).

Se você é como eu, você aprende construindo. Agora, a razão pela qual estou escrevendo este artigo é fornecer uma visão geral básica de como as blockchains funcionam construindo uma blockchain com Rust.

Soa bem? Vamos lá.

Começando

Vamos começar criando um novo projeto Rust:

cargo +nightly new blockchain
Enter fullscreen mode Exit fullscreen mode

Mude para o diretório que você acabou de criar:

cd *blockchain*
Enter fullscreen mode Exit fullscreen mode

Vamos adicionar os pacotes necessários que precisamos para construir uma blockchain:

[dependencies]
chrono = "0.4"
serde = { version = "1.0.106", features = ["derive"] }
serde_json = "1.0"
sha2 = "0.10.0"
Enter fullscreen mode Exit fullscreen mode

Em seguida, crie uma pasta chamada models, onde você manterá a maior parte da sua lógica blockchain. Nessa pasta crie dois (2) arquivos chamados blockchain.rs e block.rs.

Importe os seguintes pacotes em ambos os arquivos e salve-os:

Blockchain.rs
Enter fullscreen mode Exit fullscreen mode
use chrono::prelude::*;
// Internal module
use super::block::Block; 
Enter fullscreen mode Exit fullscreen mode
Block.rs
Enter fullscreen mode Exit fullscreen mode
use super::blockchain::Blockchain;
use chrono::prelude::*;
use sha2::{Sha256, Digest};
use serde::{Deserialize, Serialize}; 
Enter fullscreen mode Exit fullscreen mode

Se você notou que importamos use super::block::Block; em nosso arquivo blockchain.rs, estamos apenas importando a estrutura localizada em nosso arquivo block.rs aqui, não se preocupe, explicarei isso um pouco mais tarde.
Após importarmos os pacotes necessários, vamos criar um tipo em nosso arquivo blockchain.rs chamado Blocks:

type Blocks = Vec<Block>;
Enter fullscreen mode Exit fullscreen mode

Em seguida, vamos criar um tipo Blockchain em blockchain.rs e uma implementação vazia para nosso tipo Blockchain:

Uma estrutura que representa uma blockchain.
[derive(Debug)]
pub struct Blockchain {
  // O primeiro bloco a ser adicionado na cadeia.
  pub genesis_block: Block,
  // O Armazenamento para os blocos.
  pub chain: Blocks,
  // Quantidade minima de trabalho para validar um bloco.
  pub difficulty: usize
}
impl Blockchain {}
Enter fullscreen mode Exit fullscreen mode

Em seguida, vamos criar um tipo de bloco em block.rs e uma implementação vazia para o nosso tipo de bloco:

[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Block {
  // O índice em que o bloco atual será armazenado.
   pub index: u64,
   // O horário em que o bloco atual foi criado.
   pub timestamp: u64,
   // A prova de trabalho(proof of work) do bloco.
   pub proof_of_work: u64,
   // O *hash* do bloco anterior.
   pub previous_hash: String,
   // O *hash* do bloco atual..
   pub hash: String
}
impl Block {}
Enter fullscreen mode Exit fullscreen mode

Criando o bloco gênesis:

O bloco gênesis é o primeiro bloco criado em uma blockchain. Vamos criar uma função que cria um bloco gênesis para a nossa blockchain e retorna uma nova instância do tipo Blockchain.

Adicione o seguinte código em nossa implementação Blockchain em blockchain.rs:

impl Blockchain {
   pub fn new(difficulty: usize) -> Self {
     // Primeiro bloco da *blockchain*.
     let mut genesis_block = Block {
        index: 0,
        timestamp: Utc::now().timestamp_millis() as u64,
        proof_of_work: u64::default(),
        previous_hash: String::default(),
        hash: String::default()
     };
     // Cria uma nova *chain* começando do bloco gênesis.
     let mut chain = Vec::new();
     chain.push(genesis_block.clone());
     // Cria uma instancia da *blockchain*.
     let blockchain = Blockchain {
        genesis_block,
        chain,
        difficulty
     };
     blockchain
   }} 
Enter fullscreen mode Exit fullscreen mode

No código acima, fizemos o seguinte:

  • Criamos nossa instância genesis_block.

  • Adicionamos o genesis_block e criamos a blockchain em nosso tipo Blockchain.

  • Retornamos uma instância do tipo Blockchain.

Na instância genesis_block que criamos, observe como definimos nossa chave previous_hash para um valor de string vazio (String::default()) porque não haveria nenhum bloco anterior, pois o bloco gênesis é o primeiro bloco na blockchain.

Observe também que fizemos o hash do nosso genesis_block para ser uma string vazia (“”) porque ainda não calculamos o valor do hash para o nosso bloco gênesis.

Gerando o hash de um bloco

Um hash é gerado com a ajuda de criptografia e informações atuais presentes no bloco.

Vamos criar uma função em nossa implementação de bloco no arquivo block.rs que criamos chamado calculate_hash() :

 // Calcula o *hash* do bloco.
pub fn calculate_hash(&self) -> String {
  let mut block_data = self.clone();
  block_data.hash = String::default();
  let serialized_block_data = serde_json::to_string(&block_data).unwrap();
  // Calcula e retorna um valor de *hash* SHA-256.
  let mut hasher = Sha256::new();
  hasher.update(serialized_block_data);
  let result = hasher.finalize();
  format!("{:x}", result)
} 
Enter fullscreen mode Exit fullscreen mode

No código acima, nós fizemos o seguinte

  • Convertemos os dados do bloco para o formato JSON.
  • fizemos hash dos dados do bloco com o algoritmo SHA256.
  • Devolvemos o resultado do hash em base16.

Criando um novo bloco

Ótimo!, implementamos funcionalidades para criar nosso bloco gênesis e calcular os hashes de nossos blocos.

Agora vamos adicionar a funcionalidade para adicionar novos blocos a blockchain, em nosso arquivo blockchain.rs adicione esta função à implementação do tipo Blockchain:

pub fn add_block(&mut self, nonce: String) {
  let new_block = Block::new(
    self.chain.len() as u64,
    nonce,
    self.chain[&self.chain.len() - 1].previous_hash.clone()
  );
  new_block.mine(self.clone());
  self.chain.push(new_block.clone());
  println!("Novo bloco adicionado a *blockchain* -> {:?}", Novo bloco);
} 
Enter fullscreen mode Exit fullscreen mode

Aqui fizemos o seguinte:

  • Criamos uma função add_block que recebe um argumento chamado &mut self (instância do tipo Blockchain).
  • Criamos nossa instância do tipo Block.
  • Extraímos um hash do bloco usando a função de mint do tipo bloco.
  • Adicionamos o novo bloco à blockchain.

Em seguida, em nosso arquivo block.rs, adicione o seguinte código na implementação do tipo Block:

// Cria um novo bloco. O *hash* será calculado e definido automaticamente.
pub fn new (
 index: u64,
 previous_hash: String,
) -> Self {
   // Bloco atual que será criado.
   let mut block = Block {
      index: 0,
      timestamp: Utc::now().timestamp_millis() as u64,
      proof_of_work: u64::default(),
      previous_hash: String::default(),
      hash: String::default(),
   };
   block
} 
Enter fullscreen mode Exit fullscreen mode

Aqui fizemos o seguinte:

  • Criamos uma função chamada new() que recebe dois argumentos index e previous_hash.
  • Criamos nossa instância do tipo Block.
  • Geramos um hash de bloco para o nosso bloco.
  • Retornamos uma instância do tipo Block.

Mineração do novo bloco

Implementamos com sucesso a funcionalidade para criar um novo bloco.

Vamos implementar a funcionalidade para minerar novos blocos. O processo de mineração de novos blocos envolve a geração de um hash SHA256 que começa com um número desejado de 0s, que seria a dificuldade de mineração que os mineradores precisam resolver para minerar um novo bloco.

Vamos criar uma função em nosso arquivo block.rs dentro de nossa implementação do tipo Block:

// Minerar o *hash* do bloco.
pub fn mine (&mut self, blockchain: Blockchain) {
  loop {
    if !self.hash.starts_with(&"0".repeat(blockchain.difficulty)) {
      self.proof_of_work += 1;
      self.hash = self.generate_block_hash();
    } else {
       break
    }
  }
} 
Enter fullscreen mode Exit fullscreen mode

Ótimo trabalho, terminamos de implementar nossa blockchain, agora vamos testá-la.

Vamos criar um arquivo chamado mod.rs em nossa pasta models e salvar o seguinte código:

bloco de mod de pub;
pub mod blockchain; 
Enter fullscreen mode Exit fullscreen mode

Tudo o que estamos fazendo aqui é tornar os arquivos que criamos anteriormente blockchain.rs e block.rs acessíveis publicamente em nosso arquivo main.rs.

Agora vamos colar o seguinte código em nosso arquivo main.rs:

mod models;
fn main() {
   let difficulty = 1;
   let mut blockchain = models::blockchain::Blockchain::new(difficulty);
   models::blockchain::Blockchain::add_block(&mut blockchain);
} 
Enter fullscreen mode Exit fullscreen mode

Agora, para iniciar uma transação, execute cargo + nightly run.

Conclusão

Neste tutorial você aprendeu como criar uma blockchain simples do zero com Rust.

Espero que você tenha gostado de ler este artigo, você pode obter o código-fonte completo desta blockchain Rust aqui.

Este artigo foi escrito por (Enoch Chejieh) e traduzido por (Jhonattan farias), você pode encontrar o artigo original aqui.


Image description

Top comments (0)