Como é feito uma blockchain ?

Uma simples poc com todos os conceitos necessarios para a criação de uma shitcoin

Blockchains

Em um mundo cheio de palavras engraçadas e difíceis temos uma que as vezes dão calafrios para muitos devs e pessoas que trabalham com tech: Blockchain
Para começar uma blockchain ao meu ver pode ser explicada como uma lista ligada exatamente igual aquele meme do better call Saul

Nada mais que um "I know i guy who knows a guy" ou seja, conheço alguem que conheçe alguem. Outra forma de ver é como um livro-razão, daqueles bem antigos que se usava e ainda se usa em muitas vendinhas/padarias  um livro razão

Tá mas e o código? é agora a hora da realidade → esse repo aqui tem um exemplo de blockchain realemente muito simples feito em TS com o Node, usando classes da maneira mais simples e rápida o possivel e o que vamos destrinchar é o Projeto.

Transaction

Vou ser bem pratico. Vou falar das 4 classes que temos que compõem o projeto e por fim falarei do caso em uso. O primeiro que iremos falar é o mais simples e o começo de tudo é a transação por si só em termos de código é só esse simples trecho:
export default class Transaction {
  constructor(
    public amount: number,
    public payer: string,
    public payee: string
  ) {
  }
  toString(): string  {
    return JSON.stringify(this);
  }
}

Esse trecho em TS é bem expressivo e simples, uma transação é feita de um valor(número) a ser pago, um recebedor e sua chave publica, um pagador e chave publica. Possui uma função que será repetida varias vezes que é o toString(), padrão.

Block

O bloco é a peça fundamental que constroi os nós de uma blockchain, nela teremos alguns detalhes importantes, como o uso da nossa classe Transaction que declaramos anteriormente.
import crypto from "crypto";
import Transaction from "./Transaction";

export default class Block {

  public nonce = Math.round(Math.random() * 999999999);

  constructor(
    public prevHash: string | null,
    public transaction: Transaction,
    public timeStamp: number = Date.now()
  ) {
  }

  get hash() {
    const str = JSON.stringify(this);
    const hash = crypto.createHash('SHA256');
    hash.update(str).end();
    return hash.digest('hex');
  }
}

Além do import de Transaction, é necessario importar a lib que está no Node.js, a Crypto, pois usaremos um algoritimo para criar um hash usando o SHA256, para saber mais eu coloquei link nessas duas palavras diferenciadas que é importante saber antes de continuar. esse hash é como se fosse a identidade do bloco, que será utilizado no futuro, ele por fim terá uma timeStamp para saber o tempo e poder ser uma verificação no futuro, só pode haver NOVOS blocos nunca velhos.

Chain

Chegamos na parte mais doida, a chain por si só, que é formada por blocos, virando uma blockchain. Piadas a parte segue o código e vamos destrinchar as funções nele distribuidas.

import crypto from "crypto";
import Block from "./Block";
import Transaction from "./Transaction";

export default class Chain {
  public static instance = new Chain();
  chain: Block[];

  constructor() {
    this.chain = [new Block(null, new Transaction(1000, 'genesis', 'gabriel'))]
  }

  get lastBlock() {
    return this.chain[this.chain.length - 1];
  }

  mine(nonce: number) {
    let solution = 1;
    console.log('mining for prof of work...');
    while (true){
      const hash = crypto.createHash('MD5');
      hash.update((nonce + solution).toString()).end();

      const attempt = hash.digest('hex');

      if (attempt.substr(0 , 4) === '0000') {
        console.log(`Solved: ${solution}`);
        return solution;
      }
      solution += 1;
    }
  }
  addBlock(transaction: Transaction, senderPublicKey: string, signature: Buffer){
    const verifier = crypto.createVerify('SHA256');
    verifier.update(transaction.toString());

    const isValid = verifier.verify(senderPublicKey, signature);

    if (isValid) {
      const newBlock = new Block(this.lastBlock.hash, transaction);
      this.mine(newBlock.nonce);
      this.chain.push(newBlock);
    }
  }
}

Chegamos na parte mais irada, a criação de uma blockchain que é um array de blocos ligados sabendo do anterior direto. Para iniciarmos uma chain temos que fazer sua primeira instancia e quando isso ocorre, temos um evento chamado de Genesis, tipo o da biblia ou quando o banco central imprime mais dinheiro. O Genesis é só um evento de inicio para dar circulação a moeda. Com essa classe criamos a função de saber quem é o último nó no bloco, e a função de minerar que é uma parte essencial de qualquer criptomoeda, ter alguma forma de provar que a moeda que você usou em uma transação foi não só apenas usada uma vez como também é valida. Nessa função temos um loop true que faz essa validação usando um hash MD5 A prova de trabalho tem uma premissa simples que é o essencial a ser feito e entendido uma moeda com prof of work ou prova de trabalho, possui um algoritimo dificil de ser feito/ refeito/ minerado mas facilmente verificavel. Como prova de trabalho o minerador ganha uma parte da moeda como recompensa.
Temos por fim a função de adicionar bloco ao objeto, que seria feito com uma validação de prof of work conforme explicado acima

Wallet

A carteira como muitos sites tem, é nada mais que alguma forma de te identificar e ao mesmo tempo criptografar sua vida como dono de uma moeda.

import crypto from "crypto";
import Transaction from "./Transaction";
import Chain from "./Chain";

export default class Wallet {
  public publicKey: string;
  public privateKey: string;

  constructor() {
    const keypair = crypto.generateKeyPairSync("rsa", {
      modulusLength: 2048,
      publicKeyEncoding: {type: 'spki', format: 'pem'},
      privateKeyEncoding: {type: 'pkcs8', format: 'pem'},
    });
    this.publicKey = keypair.privateKey;
    this.privateKey = keypair.privateKey;
  }

  sendMoney(amount: number, payeePublicKey: string) {
    const transaction = new  Transaction(amount, this.publicKey, payeePublicKey);

    const sign = crypto.createSign('SHA256');
    sign.update(transaction.toString()).end();

    const signature = sign.sign(this.privateKey);
    Chain.instance.addBlock(transaction, this.publicKey, signature);
  }
}

Nesse trecho temos algo relativamente divertido, além dos imports, temos a criação de uma public e private key. Com elas no nosso constructor usando a lib do crypto, chamamos o uso do algoritimo de criptografia RSA além disso temos o formato pem que é aquele que temos e recebemos para quando vamos guardar keys.
Com nosso identificador publico e privado, podemos agora enviar dinheiro fazendo assinaturas, deixando seguro baseando-se em criptografia. Cada nova transação cria um novo bloco que afeta a chain como um todo.
Para desenhar e ficar facil entender o que ocorre no fim: wallet faz uma transação que cria um novo bloco que afeta nossa chain.

Conclusão

Para concluir temos nosso index.ts que faz a comprovação do que acabamos de codar e é uma ótima prova de conceito.
import Wallet from "./classes/Wallet";
import Chain from "./classes/Chain";


// usage in action

const gabriel = new Wallet();
const jon = new Wallet();
const maria = new Wallet();

gabriel.sendMoney(50, jon.publicKey);
jon.sendMoney(10, maria.publicKey);
maria.sendMoney(5, jon.publicKey);

console.log(Chain.instance);

Além dos imports necessarios, com o console log podemos ver como está a instancia da Chain de forma global.
Cada vez que enviamos dinheiro também é feito uma prova de trabalho para que não seja possivel enviar dinheiro ao mesmo tempo. Muito obrigado pela atenção e até mais

Contato

Se quiser discutir sobre qualquer assunto ou viu algum erro, não hesite em me marcar ou chamar no Twitter: @que_cara_legal
Estou sempre tentando trazer o que tenho estudado, as vezes traduzindo algums tópicos divertidos que me chamam atenção.