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
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
Mude para o diretório que você acabou de criar:
cd *blockchain*
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"
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
use chrono::prelude::*;
// Internal module
use super::block::Block;
Block.rs
use super::blockchain::Blockchain;
use chrono::prelude::*;
use sha2::{Sha256, Digest};
use serde::{Deserialize, Serialize};
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>;
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 {}
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 {}
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
}}
No código acima, fizemos o seguinte:
Criamos nossa instância
genesis_block
.Adicionamos o
genesis_block
e criamos a blockchain em nosso tipoBlockchain
.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)
}
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);
}
Aqui fizemos o seguinte:
- Criamos uma função
add_block
que recebe um argumento chamado &mut self (instância do tipoBlockchain
). - 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
}
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
}
}
}
Ó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;
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);
}
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.
Top comments (0)