Artigo original: https://www.freecodecamp.org/news/build-a-blockchain-in-golang-from-scratch/

Introdução

Com a Web 3.0 e a blockchain se tornando mais comuns a cada dia, você sabe o que é blockchain? Você conhece suas vantagens técnicas e seus casos de uso?

O objetivo deste tutorial é introduzir a tecnologia de blockchain a partir de uma perspectiva técnica, construindo uma a partir do zero.

Esqueça tudo o que você já ouviu sobre blockchain nas redes sociais. Agora, você construirá um sistema de blockchain do zero para entender realmente as entradas e saídas dessa tecnologia distribuída peer-to-peer.

Depois disso, decida sobre seu futuro e suas vantagens. Alerta de spoiler: você vai se apaixonar pelo software de programação de blockchain.

Como?

Você seguirá a história de um desenvolvedor de software que está procurando revolucionar seu bar local, através da implementação da tecnologia de blockchain para seu sistema de pagamento.

Embora a blockchain tenha vários casos de uso inegáveis, no momento, a aplicação número um são os pagamentos. Isto ocorre porque os bancos ainda estão funcionando em uma infraestrutura ineficiente, com 40 anos de idade, alimentada por arquivos CSV e FTP.

A história vem com muitos fatos engraçados e intrigantes sobre o ecossistema geral da blockchain e diferentes protocolos, como Bitcoin, Ethereum e XRP.

O que você vai criar, aprender e fazer neste tutorial?

  • Você vai configurar um projeto na linguagem Go em sua máquina local sem qualquer experiência prévia com GoLang
  • Você gerará e distribuirá seus primeiros tokens (ativos digitais) de blockchain.
  • Você desenvolverá um banco de dados controlado pela CLI em Go a partir do zero
  • Você descobrirá como poucos usuários possuem direitos em suas aplicações favoritas
  • Você descobrirá a principal proposta de valor da blockchain
  • Você tornará seu BD imutável usando uma função de hash criptográfico segura

Por isso, vamos começar a nossa história.

Conheça o protagonista, Andrej.

Andrej é dono de um bar à noite e desenvolvedor de software de dia em uma pequena cidade eslovaca chamada Bardejov.

Andrej está cansado de:

  • Programação de aplicações sólidas e à moda antiga com PHP/Java/Javascript
  • Esquecer quanto dinheiro seus amigos e clientes lhe devem por todos os shots de vodka não pagos de sexta-feira à noite
  • Passar tempo coletando e contando moedas, devolvendo troco e geralmente tocando cédulas expostas à COVID-19
  • Fazer a manutenção de diferentes fichas plásticas para pebolim, dardos, bilhar e pôquer

Andrej adoraria:

  • Ter um histórico auditável perfeito das atividades e vendas do bar para tornar seu bar compatível com as normas fiscais
  • Transformar seu bar em um ambiente autônomo, eficiente, descentralizado e seguro, no qual seus clientes possam confiar e apenas se divertir

Seu objetivo é escrever um programa simples e manter todos os saldos de seus clientes de modo virtual.

Andrej compartilha suas ideias aqui:

"Cada novo cliente me dará dinheiro, e eu creditarei para eles uma quantidade equivalente dos meus tokens (moedas/moeda criptográfica)". Os tokens representarão uma unidade monetária dentro e fora do bar.

As pessoas usarão os tokens para todas as funcionalidades do bar, desde pagar bebidas, pedir emprestado e emprestar a seus amigos, até jogar tênis de mesa, pôquer e pebolim.

Ter um bar administrado por meio de tokens gerará um valor imenso para meus clientes. Ao contrário da minha concorrência e de outros bares nesta rua, onde os clientes só gastam dinheiro e conseguem uma ressaca em troca, os clientes que tiverem fichas do meu bar terão direito de acionistas.

Semelhante a possuir uma grande parte das ações de uma empresa, como a Apple ou a Microsoft, os clientes que possuem esses tokens de bar poderão decidir como o bar funcionará através de votação e decisão sobre:

  • preços das bebidas
  • horário de funcionamento
  • novas funcionalidades (TV, jukebox...)
  • design interior e exterior
  • alocação de lucros
  • etc.

Ah, isso será um sonho para programação!

Chamarei os tokens de: tokens do bar das blockchain, ou TBB!"

Agora que Andrej compartilhou seu sonho, vamos começar.

Sumário

Requisitos

Vamos nos aprofundar em nosso tutorial. Recomendo mais de 2 anos de experiência em programação em Java/PHP/Javascript ou outra linguagem similar à Go.

Se você quiser ter uma boa introdução rápida para começar, aqui está um curso gratuito (em inglês) que ajudará você.

Você também pode completar as 17 aulas oficiais de Um tour por Go para se familiarizar com a sintaxe do idioma e conceitos básicos (cerca de 20 minutos).

Por que Go?

Porque, assim como a blockchain, é uma tecnologia fantástica para toda a sua carreira de programação. Go é uma linguagem da moda e desenvolvedores de Go são mais bem pagos do que a média das posições em Java/PHP/Javascript.

Go é otimizado para a arquitetura de CPUs multi-core. Você pode gerar milhares de threads leves (rotinas do Go) sem problemas. É extremamente prático para software paralelos e simultâneos, tais como redes de blockchain.

Ao escrever seu software em Go, você atinge um nível semelhante ao do C++ em termos de desempenho, desde o início, sem se matar por ter esquecido de liberar a memória.

Go também compila para binário, o que o torna muito portátil.

Configurar o projeto

Este artigo tem um repositório dedicado e de código aberto no Github, com o código-fonte completo para que você possa compilar o código e executar o programa em sua própria máquina local.

Se você ficar preso em qualquer capítulo ou em uma linha de código em particular, crie uma issue no Github do repositório descrevendo seu problema e eu o ajudarei o quanto antes!

Visite o repositório no Github e siga as instruções de instalação.

54218031

01 | O banco de dados MVP

git checkout c1_genesis_json

Andrej dominou os bancos de dados relacionais em SQL nos anos 90. Ele sabe como fazer modelos de dados avançados e como otimizar as consultas em SQL.

Chegou a hora de Andrej alcançar a inovação e começar a criar software para a web 3.0.

Por sorte, após ler o livro "The Lean Startup" na semana passada, Andrej percebe que ainda não deveria projetar demais a solução. Assim, ele escolhe um arquivo JSON simples, mas eficaz, para ser o banco de dados e o produto viável mínimo, ou MVP (do inglês, minimum viable product), do bar.

No início, havia um banco de dados centralizado primitivo.

Resumo:

A blockchain é um banco de dados.

Usuário 1, Andrej

Segunda-feira, 18 de março.

Andrej gera 1 milhão de tokens de utilidade.

No mundo da blockchain, os tokens são unidades dentro do banco de dados da blockchain. Seu valor real em espécie flutua com base em sua demanda e popularidade.

Cada blockchain tem um arquivo "Genesis". O arquivo "Genesis" é usado para distribuir os primeiros tokens aos participantes iniciais da blockchain.

Tudo começa com um simples genesis.json de teste.

Andrej cria o arquivo ./database/genesis.json, onde ele define que o banco de dados do bar da blockchain terá 1 milhão de tokens e que todas elas pertencerão a Andrej:

{
  "genesis_horario": "2019-03-18T00:00:00.000000000Z",
  "chain_id": "the-blockchain-bar-ledger",
  "saldo": {
      "andrej": 1000000
  }
}

Os tokens precisam ter uma "utilidade" real, ou seja, um caso de uso. Os usuários devem ser capazes de pagar com eles a partir do primeiro dia!

Andrej deve estar em conformidade com as regulamentações da lei. É ilegal a emissão de valores não registrados. Por outro lado, os tokens de utilidade estão em conformidade, então ele imprime e cola imediatamente um novo cartaz com os preços na porta do bar.

Andrej atribui um valor monetário inicial a seus tokens para poder trocá-los por euro, dólar ou outra moeda.

1 token TBB = 1€

| Item                      	 | Preco   |
| ------------------------------ | ------- |
| Dose de vodka                	 | 1   TBB |
| Suco de laranja           	 | 5   TBB |
| Hamburguer                	 | 2   TBB |
| Garrafa de vodka Crystal Head  | 950 TBB |

Andrej também decide que deve receber 100 tokens por dia para manter o banco de dados e por ter tido uma ideia tão brilhante e disruptiva.

Fatos interessantes

A primeira genesis Ether (ETH) sobre a blockchain Ethereum foi criada e distribuída aos primeiros investidores e desenvolvedores da mesma maneira que o token de utilidade de Andrej.
Em 2017, durante um boom das ofertas iniciais de moedas (do inglês, Initial Coin Offers, ou ICO) na rede de blockchain Ethereum, os fundadores do projeto escreveram e apresentaram whitepapers aos investidores. Um whitepaper é um documento técnico que esboça uma questão complexa e uma possível solução, destinada a educar e esclarecer sobre um assunto específico. No mundo da blockchain, um whitepaper serve para delinear as especificações de como essa blockchain em particular será e se comportará uma vez desenvolvida.
Os projetos de blockchain aumentaram entre 10 e 300 milhões de euros por ideia de whitepaper.
Em troca de dinheiro (o "financiamento" das ICOs), os nomes dos investidores seriam incluídos nos "balanços de genesis" iniciais, semelhante ao que Andrej fez. As esperanças dos investidores em uma ICO estão no fato de que as moedas de genesis subam de valor e que as equipes entreguem a blockchain delineada.
Naturalmente, nem todas as ideias de whitepaper se concretizam. Investimentos massivos perdidos por ideias pouco claras ou incompletas são a razão pela qual a blockchain recebeu cobertura negativa na mídia através dessas ICOs e para alguns ainda a considerarem uma modinha. A tecnologia da blockchain subjacente, porém, é fantástica e útil, como você aprenderá mais neste artigo. Ela tem sido abusada por alguns maus atores.

Resumo:

A blockchain é um banco de dados.

O fornecimento de tokens, o balanço inicial do usuário e as configurações globais da blockchain são definidas em um arquivo genesis.

02 | Alterando o estado global do BD

git checkout c2_db_changes_txt

Festa chata

Segunda-feira, 25 de Março.

Após uma semana de trabalho, as instalações do bar estão prontas para aceitar os tokens. Infelizmente, ninguém aparece. Então, Andrej pede três doses de vodka para si mesmo e escreve as mudanças no banco de dados em um pedaço de papel:

andrej-3;   // 3 doses de vodka
andrej+3;   // tecnicamente comprando de seu próprio bar
andrej+700; // Recompensa por uma semana de trabalho (7x100 por dia)

Para evitar recalcular o estado mais recente do saldo de cada cliente, Andrej cria um arquivo ./database/state.json, que armazena os saldos em um formato agregado.

Novo estado do BD:

{
  "saldo": {
      "andrej": 1000700
  }
}

Bônus para BabaYaga

Terça-feira, 26 de Março.

Para trazer o público até seu bar, Andrej anuncia um bônus exclusivo de 100% para todos que adquirirem os tokens TBB nas próximas 24 horas.

Ele recebe sua primeira cliente, chamada BabaYaga. BabaYaga pré-compra mil euros em tokens e, para comemorar, gasta imediatamente 1 TBB para uma dose de vodka. Ela tem um problema com a bebida.

Transações do BD escritas em um pedaço de papel:

andrej-2000;   // transfererência para BabaYaga
babayaga+2000; // pré-compra com 100% bônus
babayaga-1;
andrej+1;
andrej+100;    // 1 dia de sol nascendo

Novo estado do BD:

{
  "saldo": {
      "andrej": 998801,
      "babayaga": 1999
  }
}

Fatos interessantes

Os projetos de ICO (ofertas iniciais de moedas, baseadas em whitepaper) de blockhain frequentemente distribuem os tokens de genesis com diferentes bônus, dependendo de quantos deles você compra e de você ter feito isso rapidamente. As equipes oferecem, em média, 10-40% de bônus aos "participantes" iniciais.
A palavra "investidor" é evitada, de modo que os reguladores legais não considerarão os tokens como um valor não registrado. Os projetos argumentariam que seu produto principal, tokens de blockchain, funcionam como "milhas de vôo ou pontos de fidelidade".
Os "participantes", mais tarde, fazem até 1.000% de seu investimento vendendo ao público através de um intercâmbio vários meses depois.

Resumo:

A blockchain é um banco de dados.

O fornecimento de tokens, o balanço inicial do usuário e as configurações globais da blockchain, você define em um arquivo Genesis.

Os balanços de Genesis indicam qual era o estado original da blockchain e nunca são atualizados depois.

As mudanças de estado do banco de dados são chamadas de transações (TX).

03 | Evento monolítico x transação

git checkout c3_state_blockchain_component

Os desenvolvedores acostumados à arquitetura de fornecimento de eventos devem ter reconhecido imediatamente os princípios familiares por trás das transações. Eles estão corretos.

As transações das blockchain representam uma série de eventos. O banco de dados é um estado final agregado, calculado após a repetição de todas as transações em uma sequência específica

Andrej programando

Terça-feira à noite, 26 de março.

É uma noite relaxante de terça-feira para Andrej. Comemorando seu primeiro cliente, ele decide jogar Starcraft e limpar sua máquina de desenvolvimento local, removendo algumas fotos antigas.

Infelizmente, ele pressionou prematuramente a tecla Enter ao digitar um comando de comando de remoção no terminal, sudo rm -rf /. Xiiii!

Todos os seus arquivos, incluindo os arquivos genesis.json e state.json do bar, desapareceram.

Andrej, sendo um desenvolvedor sênior, gritou repetidamente algumas palavras bem alto por alguns segundos, mas não entrou em pânico!

Embora ele não tivesse um back-up, ele tinha algo melhor – um pedaço de papel com todas as transações do banco de dados. A única coisa que ele precisa fazer é reproduzir todas as transações uma a uma e o estado de seu banco de dados será recuperado.

Impressionado com as vantagens da arquitetura baseada em eventos, ele decide ampliar sua solução de banco de dados MVP. Cada atividade do bar, como a compra individual de bebidas, DEVE ser registrada dentro do banco de dados da blockchain.

Cada consumidor será representado no BD utilizando uma estrutura de conta:

type Conta string

Cada Transação (TX – uma mudança de banco de dados) terá os quatro atributos seguintes: de, para, valor e dados.

O atributo de dados com um valor possível (recompensa) captura o bônus de Andrej por inventar a blockchain e aumenta artificialmente a oferta total inicial de tokens TBB (inflação).

type Tx struct {
   De  Account `json:"de"`
   Para    Account `json:"para"`
   Valor uint    `json:"valor"`
   Dado  string  `json:"dado"`
}

func (t Tx) IsReward() bool {
   return t.Dado == "recompensa"
}

O BD de Genesis permanecerá com um arquivo JSON:

{
  "genesis_horario": "2019-03-18T00:00:00.000000000Z",
  "chain_id": "the-blockchain-bar-ledger",
  "saldo": {
      "andrej": 1000000
  }
}

Todas as transações, previamente escritas em um pedaço de papel, serão armazenadas em um banco de dados local de arquivos de texto chamado tx.db, serializado em formato JSON e separado por caracteres de quebra de linha:

{"de":"andrej","para":"andrej","valor":3,"dado":""}
{"de":"andrej","para":"andrej","valor":700,"dado":"recompensa"}
{"de":"andrej","para":"babayaga","valor":2000,"dado":""}
{"de":"andrej","para":"andrej","valor":100,"dado":"recompensa"}
{"de":"babayaga","para":"andrej","valor":1,"dado":""}

O componente mais crucial do banco de dados, que encapsula toda a lógica comercial será o Estado:

type Estado struct {
   Saldos   map[Conta]uint
   txMempool []Tx

   dbFile *os.File
}

A estrutura do Estado saberá sobre todos os saldos de usuários, quem transferiu os tokens TBB para quem e quantos foram transferidos.

É construído através da leitura do saldo inicial de usuários do arquivo genesis.json:

func NewStateFromDisk() (*Estado, error) {
   // Obter o diretorio de trabalho atual
   cwd, err := os.Getwd()
   if err != nil {
      return nil, err
   }

   genFilePath := filepath.Join(cwd, "database", "genesis.json")
   gen, err := loadGenesis(genFilePath)
   if err != nil {
      return nil, err
   }

   saldo := make(map[Conta]uint)
   for conta, saldo := range gen.Saldos {
      saldos[conta] = saldo
   }

Em seguida, os balanços do Estado de genesis são atualizados através da reprodução sequencial de todos os eventos do banco de dados do tx.db:

   txDbFilePath := filepath.Join(cwd, "database", "tx.db")
   f, err := os.OpenFile(txDbFilePath, os.O_APPEND|os.O_RDWR, 0600)
   if err != nil {
      return nil, err
   }

   scanner := bufio.NewScanner(f)
   estado := &Estado{saldos, make([]Tx, 0), f}

   // Iterar sobre cada linha do arquivo tx.db
   for scanner.Scan() {
      if err := scanner.Err(); err != nil {
         return nil, err
      }

      // Converter TX codificado pelo JSON em um objeto (estrutura)
      var tx Tx
      json.Unmarshal(scanner.Bytes(), &tx)

      // Reconstruir o Estado (saldos de usuários),
      // como uma série de eventos
      if err := estado.apply(tx); err != nil {
         return nil, err
      }
   }

   return estado, nil
}

O componente Estado é responsável por:

  • Adicionar novas transações ao Mempool
  • Validar as transações contra o Estado atual (saldo suficiente do remetente)
  • Mudar o estado
  • Salvar transações persistentes em disco
  • Calcular os saldos de contas através da repetição de todas as transações desde Genesis em uma seqüência

Adicionar novas transações ao Mempool:

func (s *Estado) Add(tx Tx) error {
   if err := s.apply(tx); err != nil {
      return err
   }

   s.txMempool = append(s.txMempool, tx)

   return nil
}

Persistir as transações em disco:

func (s *Estado) Persist() error {
   // Faça uma cópia do mempool porque o s.txMempool será modificado
   // no laço abaixo
   mempool := make([]Tx, len(s.txMempool))
   copy(mempool, s.txMempool)

   for i := 0; i < len(mempool); i++ {
      txJson, err := json.Marshal(mempool[i])
      if err != nil {
         return err
      }

      if _, err = s.dbFile.Write(append(txJson, '\n')); err != nil {
         return err
      }

      // Remover o TX escrito em um arquivo do mempool
      s.txMempool = s.txMempool[1:]
   }

   return nil
}

Mudar, validar o estado:

func (s *Estado) apply(tx Tx) error {
   if tx.IsReward() {
      s.Saldos[tx.To] += tx.Valor
      return nil
   }

   if tx.Valor > s.Saldos[tx.De] {
      return fmt.Errorf("saldo insuficiente")
   }

   s.Saldos[tx.De] -= tx.Valor
   s.Saldos[tx.Para] += tx.Valor

   return nil
}

Construir uma interface de linha de comando (CLI)

Terça-feira à noite, 26 de março.

Andrej quer ter uma maneira conveniente de adicionar novas transações ao seu banco de dados e listar os últimos saldos de seus clientes. Como os programas Go compilam para binário, ele faz uma CLI para seu programa.

A maneira mais fácil de desenvolver programas baseados em CLI em Go é usando a biblioteca de terceiros github.com/spf13/cobra.

Andrej inicializa o gerenciador de dependências de Go para seu projeto, chamado go modules:

cd $GOPATH/src/github.com/web3coach/the-blockchain-way-of-programming-newsletter-edition

go mod init github.com/web3coach/the-blockchain-way-of-programming-newsletter-edition

O comando Go modules buscará automaticamente qualquer biblioteca a que você se referir dentro de seus arquivos Go.

Andrej cria um diretório chamado cmd, com um subdiretório tbb:

mkdir -p ./cmd/tbb

Dentro, ele cria um arquivo main.go, servindo como o ponto de entrada da CLI do programa:

package main

import (
    "github.com/spf13/cobra"
    "os"
    "fmt"
)

func main() {
    var tbbCmd = &cobra.Command{
        Use:   "tbb",
        Short: "The Blockchain Bar CLI",
        Run: func(cmd *cobra.Command, args []string) {
        },
    }
    
    err := tbbCmd.Execute()
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
}

Os programas Go são compilados usando o comando install:

go install ./cmd/tbb/...

go: finding github.com/spf13/cobra v1.0.0
go: downloading github.com/spf13/cobra v1.0.0
go: extracting github.com/spf13/cobra v1.0.0

O Go detectará as bibliotecas ausentes e as buscará automaticamente antes de compilar o programa. Dependendo de seu $GOPATH, o programa resultante será salvo na pasta $GOPATH/bin.

echo $GOPATH

/home/web3coach/go

which tbb

/home/web3coach/go/bin/tbb

Você pode executar o tbb de seu terminal agora, mas ele não fará nada porque a função Run dentro do arquivo main.go está vazia.

A primeira coisa que Andrej precisa é de suporte de versão para seu programa tbb da CLI.

Ao lado do arquivo main.go, ele cria um comando version.go:

package main

import (
    "fmt"
    "github.com/spf13/cobra"
)

const Major = "0"
const Minor = "1"
const Fix = "0"
const Verbal = "Adicionar TX e listar saldos"

var versionCmd = &cobra.Command{
    Use:   "versão",
    Short: "Descreve a versão.",
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Printf("Versão: %s.%s.%s-beta %s", Major, Minor, Fix, Verbal)
    },
}

Ele compila o programa e o executa:
go install ./cmd/tbb/...
tbb version

Versão: 0.1.0-beta Adicionar TX e listar saldos

Perfeito.

De modo idêntico ao arquivo version.go, ele cria um arquivo balance.go:

func saldosCmd() *cobra.Command {
    var saldosCmd = &cobra.Command{
        Use:   "saldos",
        Short: "Interage com saldos (lista...).",
        PreRunE: func(cmd *cobra.Command, args []string) error {
            return incorrectUsageErr()
        },
        Run: func(cmd *cobra.Command, args []string) {
        },
    }

    saldosCmd.AddCommand(saldosListaCmd)

    return saldosCmd
}

O comando saldos será responsável por carregar o último estado do BD e imprimi-lo para a saída padrão:

var saldosListaCmd = &cobra.Command{
    Use:   "list",
    Short: "Lista todos os saldos.",
    Run: func(cmd *cobra.Command, args []string) {
        estado, err := database.NewStateFromDisk()
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
        }
        defer estado.Close()

        fmt.Println("Saldos das contas:")
        fmt.Println("__________________")
        fmt.Println("")
        for conta, saldo := range estado.Saldos {
            fmt.Println(fmt.Sprintf("%s: %d", conta, saldo))
        }
    },
}

Andrej verifica se o comando funciona como esperado. Ele deve imprimir os saldos exatos definidos no arquivo Genesis porque o arquivo tx.db ainda está vazio.

go install ./cmd/tbb/...

tbb saldos list

Saldos das contas:
__________________
andrej: 1000000

Funciona bem! Agora, ele só precisa de um comando para registrar a atividade do bar.

Andrej cria o comando ./cmd/tbb/tx.go:

func txCmd() *cobra.Command {
    var txsCmd = &cobra.Command{
        Use:   "tx",
        Short: "Interage com as txs (adicionar...).",
        PreRunE: func(cmd *cobra.Command, args []string) error {
            return incorrectUsageErr()
        },
        Run: func(cmd *cobra.Command, args []string) {
        },
    }

    txsCmd.AddCommand(txAddCmd())

    return txsCmd
}

O comando tbb tx add utiliza a função Estado.Adicionar(tx) para a persistência dos eventos do bar no sistema de arquivos:

func txAddCmd() *cobra.Command {
    var cmd = &cobra.Command{
        Use:   "add",
        Short: "Adiciona novo TX ao banco de dados.",
        Run: func(cmd *cobra.Command, args []string) {
            de, _ := cmd.Flags().GetString(flagDe)
            para, _ := cmd.Flags().GetString(flagPara)
            valor, _ := cmd.Flags().GetUint(flagValor)

            deConta := database.NewAccount(de)
            paraConta := database.NewAccount(para)
            
            tx := database.NewTx(deConta, paraConta, valor, "")

            estado, err := database.NewStateFromDisk()
            if err != nil {
                fmt.Fprintln(os.Stderr, err)
                os.Exit(1)
            }
            
            // Deferir ao final da execução dessa função
            // A executação da seguinte declaração (fechar o arquivo DB com todos os TXs)
            defer estado.Close()
            
            // Adicionar o TX a um array em memória (pool)
            err = estado.Add(tx)
            if err != nil {
                fmt.Fprintln(os.Stderr, err)
                os.Exit(1)
            }
            
            // Limpa os TXs do mempool para o disco
            err = estado.Persist()
            if err != nil {
                fmt.Fprintln(os.Stderr, err)
                os.Exit(1)
            }

            fmt.Println("TX adicionada com sucesso ao ledger.")
        },
    }

O comando tbb tx add tem 3 flags obrigatórias: --de, --para e --valor.

cmd.Flags().String(flagDe, "", "De que conta enviar os tokens")
cmd.MarkFlagRequired(flagDe)

cmd.Flags().String(flagPara, "", "Para que conta enviar os tokens")
cmd.MarkFlagRequired(flagPara)

cmd.Flags().Uint(flagValor, 0, "Quantos tokens enviar")
cmd.MarkFlagRequired(flagValor)

return cmd

A CLI está feita!

Andrej migra todas as transações do papel para o novo BD:

tbb tx add --de=andrej --para=andrej --valor=3

tbb tx add --de=andrej --para=andrej --valor=700

tbb tx add --de=babayaga --para=andrej --valor=2000

tbb tx add --de=andrej --para=andrej --valor=100 --dado=recompensa

tbb tx add --de=babayaga --para=andrej --valor=1

Leia todos os TXs a partir do disco e calcule o estado mais recente:

tbb saldos list

Saldos das contas:
__________________
andrej: 998801
babayaga: 1999

Dados do bar restaurados com sucesso! Ufa! Que noite!

Sobre a biblioteca Cobra CLI

O bom da biblioteca Cobra para a programação da CLI está nas características adicionais que ela traz consigo. Por exemplo, agora, você pode executar o comando tbb help e imprimirá todos os subcomandos registrados na TBB com instruções sobre como usá-los.

 tbb help

The Blockchain Bar CLI

Usage:
  tbb [flags]
  tbb [command]

Available Commands:
  balances    Interage com balanços (list...).
  help        Ajuda sobre qualquer comando
  tx          Interage com txs (add...).
  version     Descreve a versão.

Flags:
  -h, --help   ajuda para tbb

Use "tbb [comando] --help" para mais informações sobre um comando.

Fatos interessantes

A perda acidental de dados dos clientes é normal no mundo corporativo nos dias de hoje. A blockchain corrige isso descentralizando o armazenamento de dados.
Há um truque que Andrej introduziu no programa ao pular a verificação de saldos para os TX marcados como "recompensas". Bitcoin e Ethereum funcionam da mesma forma. O saldo da Conta que minerou um bloco aumenta do nada como um assunto de inflação total de fornecimento dos tokens, que afeta toda a cadeia. O fornecimento total de bitcoins é limitado a 21M BTC. Você aprenderá mais sobre "mineração" e "blocos" posteriormente.
Os componentes State (estado) e Mempool não são exclusivos deste programa. Andrej escolheu os nomes e designs para combinar com um modelo simplificado da go-Ethereum, para que você tenha uma ideia do código fonte central do Ethereum.

Resumo:

A blockchain é um banco de dados.

O fornecimento de tokens, os balanços iniciais dos usuários e as configurações globais da blockchain são definidos em um arquivo Genesis.

Os balanços de Genesis indicam qual era o estado original da blockchain e nunca são atualizados depois.

As mudanças de estado do banco de dados são chamadas Transações (TX).

As transações são eventos ao estilo antigo, que representam ações dentro do sistema.

Código de estudo

Commit: 5d4b0b

unlock_blockchain_components_state

Vamos falar sobre a ganância.

04 | Os humanos são gananciosos

git checkout c4_caesar_transfer

A ganância típica dos negócios

Quarta-feira, 27 de março.

BabaYaga investiu um pouco demais. Ela esqueceu que o pagamento do aluguel do apartamento estava chegando e, agora, não tem o dinheiro. BabaYaga chama o proprietário de seu apartamento, César.

BabaYaga: Ei, César, sinto muito, mas não tenho dinheiro para pagar o aluguel este mês...

Caesar: Por que não?

BabaYaga: O ICO do Blockchain Bar ofereceu um bônus enorme e eu comprei 2000 tokens no valor de apenas mil euros. Foi um grande negócio!

César: Do que você está falando? O que é um ICO? O que são tokens? Você pode me pagar de algum outro modo?

BabaYaga: Ah, outra vez, não. Eu posso dar mil tokens TBB, que valem mil euros, e você pode usá-los no bar para pagar suas bebidas! Deixe-me ligar para o dono do bar, Andrej, e fazer a transferência!

César: Muito bem... eu vou aceitar.

Andrej realiza a transferência, mas decide cobrar mais 50 tokens de TBB por ter de fazer os procedimentos. Ele não quer, MAS os acionistas do bar que investiram nele há alguns anos estão forçando-o a gerar lucro o mais rápido possível.

BabaYaga não vai ter problemas com esta taxa relativamente pequena, muito provavelmente, diz Andrej a si mesmo. No final, somente ele tem o acesso ao BD.

// Pagamento do aluguel

tbb tx add --de=babayaga --para=cesar --valor=1000

// Cobrança de taxa oculta

tbb tx add --de=babayaga --para=andrej --valor=50

// Nova recompensa por mais um dia de manutenção do BD

tbb tx add --de=andrej --para=andrej --valor=100 --dado=recompensa

Fatos interessantes

O caso de uso número um da blockchain é o bancário. Muitos projetos de blockchain visam otimizar o câmbio nacional e internacional de dinheiro através de diferentes canais de moedas (XRP).
Outros projetos enfocam a liberdade e a identidade própria (SSI, do inglês, Self-sovereign identity) – um movimento digital que reconhece que um indivíduo deve possuir e controlar sua identidade e dinheiro sem as autoridades administrativas intervenientes ou outros intermediários centralizados. A SSI permite que as pessoas interajam no mundo digital com a mesma liberdade e capacidade de confiança que interagem no mundo off-line. (Bitcoin / Ethereum)
Aqui estão alguns fatos interessantes que explicam o porquê de a blockchain ser um ajuste perfeito para substituir a infraestrutura bancária atual de seu banco.
O bom dos tokens é sua fungibilidade - ou seja, sua capacidade de serem comercializados, com cada unidade sendo tão utilizável quanto a próxima. A realização de uma transferência de conta para conta pode ser feita simplesmente mudando o estado do banco de dados. As moedas criptográficas são negociáveis 24 horas por dia, 7 dias por semana.
Você não pode negociar ações diretamente. Você precisa passar por um corretor que participa de uma porcentagem da transação total como taxa (1-3% a 7% do lucro médio anual).
Uma transferência bancária internacional leva entre 3-10 dias úteis e pode custar até 5% do valor transferido! Se você estiver enviando $10.000, poderá ter que pagar até $500. A tecnologia por trás disso nos últimos 40 anos? FTP + arquivos CSV.
Você acha que o mercado de ações é justo? Os bancos, índices e ações são altamente centralizados e controlados por governos e grupos privados de Wall Street. O mercado livre? Wall Street controla o quanto os preços podem saltar/cair em um único dia.
Como exemplo, Wall Street suspendeu a negociação do "Índice S&P 500" após uma queda de 7% para proteger seus investidores e fundos especulativos de perder dinheiro das pessoas que venderam suas ações durante março de 2020, após as notícias da COVID. Posteriormente, o FED imprimiu trilhões de dólares para eles mesmos para apoiar o preço das ações. Se você é um desenvolvedor que gosta de economizar dinheiro e evitar dívidas, suas economias acabarão perdendo valor de um dia para o outro por uma porcentagem ainda desconhecida.
Muitos países estão entrando em rendimentos negativos, um território inexplorado com consequências desconhecidas. O que isto significa? Em breve você terá que pagar ao banco para manter suas economias. Inflação no seu melhor. Você está sendo obrigado a gastar seu dinheiro para apoiar um sistema que você não controla.

Código de estudo

Commit: 00d6ed

05 | Por que precisamos da blockchain

git checkout c5_broken_trust

BabaYaga busca justiça

Quinta-feira, 28 de março.

BabaYaga entra no bar para seu aniversário.

BabaYaga: Ei, Andrej! Hoje é meu aniversário! Traga-me sua garrafa mais cara!

Andrej: Feliz aniversário! Aqui está: Vodka Crystal Head. Mas você precisa comprar um token TBB adicional. A garrafa custa 950 tokens, e seu saldo é de 949.

BabaYaga: O quê?! Meu saldo deveria ser de 999 TBB!

Andrej: A transferência de fundos para César que você solicitou na semana passada custou 50 tokens.

BabaYaga: Isto é inaceitável! Eu nunca concordaria com uma taxa tão alta. Você não pode fazer isto, Andrej. Confiei em seu sistema, mas você é tão pouco confiável quanto qualquer outro proprietário de empresa. As coisas devem mudar!

Andrej: Muito bem, veja. Você é minha cliente mais fiel e eu não queria cobrar de você, mas meus acionistas me obrigaram.

Deixe-me reprogramar meu sistema e torná-lo completamente transparente e descentralizado. Afinal, se todos fossem capazes de interagir com o bar sem passar por mim, isso melhoraria significativamente a eficiência do bar e equilibraria o nível de confiança!

  • Pedir bebidas levaria segundos ao invés de minutos
  • Os clientes que esqueceram suas carteiras em casa poderiam pedir emprestado ou emprestar tokens um ao outro
  • Eu não teria que me preocupar em perder os dados dos clientes (novamente), pois todos teriam uma cópia dos mesmos
  • O banco de dados seria imutável, portanto, uma vez que todos estivessem de acordo sobre um estado específico, ninguém mais poderia mudá-lo ou modificar maliciosamente a história. A imutabilidade também ajudaria nas auditorias fiscais anuais!
  • Se os acionistas quisessem introduzir novas taxas ou aumentar as taxas atuais, todos os envolvidos no sistema de blockchain notariam e teriam que concordar com ele. Os usuários e proprietários de empresas teriam até mesmo que se engajar em algum sistema de governança descentralizada em conjunto, baseado na votação, provavelmente. Em caso de desacordo, os usuários se afastam com todos os seus dados!

BabaYaga: Bem, certamente soa bem, mas será que isso é mesmo possível?

Andrej: Sim, eu acho que sim. Com um pouco de hashing, listas vinculadas, estrutura de dados imutável, replicação distribuída e criptografia assimétrica!

BabaYaga: Não faço ideia do que você acabou de dizer, mas vá em frente e faça suas nerdices, Andrej!

Fatos interessantes

Os mineradores Bitcoin e Ethereum também recebem recompensas a cada 15 minutos, aproximadamente, por executar os servidores da blockchain (os nós) e validar as transações.
A cada 15 minutos, um minerador de Bitcoins recebe 12,5 BTC ($100 mil no momento em que este artigo foi escrito) para cobrir o custo de seus servidores + obter algum lucro.
A rede das Bitcoins consome tanta eletricidade quanto o país inteiro da Áustria. Ela é responsável por 0,29% do consumo anual de eletricidade mundial.
Anualmente, ela consome 76,84 TWh, produzindo 36,50 Mt de rastro de carbono de CO2 (Nova Zelândia). Fonte.
Por quê? Você aprenderá mais tarde onde você programará um algoritmo de mineração de Bitcoin a partir do zero!
Observação: nosso algoritmo consumirá um pouco menos de eletricidade🙂

Resumo:

O software, quando não é de código aberto, dá acesso centralizado aos dados privados, o que permite que apenas um punhado de pessoas tenha muito poder. Os usuários não têm escolha, e os acionistas estão no negócio para ganhar dinheiro.

Os desenvolvedores da blockchain visam desenvolver protocolos onde os empresários e usuários das aplicações se sinergizem em uma relação transparente e auditável. As especificações do sistema da blockchain devem ser bem definidas desde o início e só devem mudar se seus usuários o apoiarem.

A blockchain é um banco de dados. O fornecimento de tokens, os saldos iniciais de usuários e as configurações globais da blockchain são definidos em um arquivo Genesis. Os balanços Genesis indicam qual era o estado original da blockchain e nunca são atualizados posteriormente.

As mudanças de estado do banco de dados são chamadas Transações (TX). Transações são eventos à moda antiga que representam ações dentro do sistema.

Código de estudo

Commit: 642045

06 | O hash imutável

git checkout c6_immutable_hash

A dificuldade técnica começa com esta seção! Os conceitos só vão ficar mais desafiadores mas, ao mesmo tempo, muito empolgantes. Apertem os cintos 😀

Como programar um banco de dados imutável?

Sexta-feira, 29 de março.

Se Andrej quer descobrir como programar um BD imutável, ele tem que entender porque outros sistemas de banco de dados são mutáveis por padrão.

Ele decide analisar uma tabela poderosa do BD do MySQL:

| id | nome     | saldo   |
| -- | -------- | ------- |
| 1  | Andrej   | 998951  |
| 2  | BabaYaga | 949     | 
| 3  | Caesar   | 1000    |

No BD MySQL, qualquer pessoa com acesso e uma razão suficientemente boa pode realizar uma atualização de tabela como, por exemplo:

UPDATE saldo_usuario SET saldo = saldo + 100 WHERE id > 1

A atualização de valores através de diferentes linhas é possível porque as linhas da tabela são independentes, mutáveis e o estado mais recente não é aparente.

Qual é a última mudança no BD? A última coluna mudou? Qual é a última linha inserida? Como Andrej pode saber qual linha foi apagada recentemente? Se as linhas e o estado da tabela estivessem firmemente unidos, dependentes, a atualização da linha 1 geraria uma tabela completamente nova e diferente. Andrej conseguiria sua imutabilidade.

Como você pode saber se algum byte em um banco de dados mudou?

Imutabilidade via funções de hash

Hashing é o processo de tomar uma string de entrada de comprimento arbitrário e produzir uma string de hash de comprimento fixo. Qualquer mudança na entrada, resultará em um hash novo e diferente.

package main

import (
	"crypto/sha256"
	"fmt"
)

func main() {
	saldosHash := sha256.Sum256([]byte("| 1 | Andrej | 99895 |"))
	fmt.Printf("%x\n", saldosHash)
	// Output: 6a04bd8e2...f70a3902374f21e089ae7cc3b200751
	
	// Mudar o saldo de 99895 -> 99896
	
	saldosHashDiff := sha256.Sum256([]byte("| 1 | Andrej | 99896 |"))
	fmt.Printf("%x\n", saldosHashDiff)
	// Saída: d04279207...ec6d280f6c7b3e2285758030292d5e1
}

Experimente: https://play.golang.org/p/FTPUa7IhOCE

Andrej também requer algum nível de segurança para seu banco de dados. Por isso, ele decide por uma função de hash criptográfico com as seguintes propriedades:

  • é determinista – a mesma mensagem resulta sempre no mesmo hash
  • é rápida para calcular o valor de hash para qualquer mensagem dada
  • é inviável gerar uma mensagem a partir de seu valor hash, exceto tentando todas as mensagens possíveis
  • uma pequena mudança em uma mensagem deve mudar o valor de hash tão extensivamente que o novo valor de hash pareça não estar relacionado com o antigo valor de hash
  • é inviável (texto em inglês) encontrar duas mensagens diferentes com o mesmo valor de hash
hash_fruit
Exemplo de hashing com frutas – fonte da imagem

Implementando o hashing do conteúdo do BD

Sábado à noite, 30 de março.

Andrej modifica a função Persist() para devolver um novo hash de conteúdo, Snapshot, toda vez que uma nova transação é persistida.

type Snapshot [32]byte

O Snapshot é produzido por esta nova função de hashing seguro sha256:

func (s *Estado) doSnapshot() error {
   // Lê novamente todo o arquivo desde o primeiro byte
   _, err := s.dbFile.Seek(0, 0)
   if err != nil {
      return err
   }

   txsData, err := ioutil.ReadAll(s.dbFile)
   if err != nil {
      return err
   }
   s.snapshot = sha256.Sum256(txsData)

   return nil
}

A função doSnapshot() é chamada pela função Persist() modificada. Quando uma nova transação é escrita no arquivo tx.db, Persist() faz o hash de todo o conteúdo do arquivo e retorna seu hash uma "impressão digital" de 32 bytes.

persist_function
Persist() faz o hash do arquivo tx.db inteiro

A partir deste momento, todos podem se referir com 100% de confiança e segurança a qualquer estado particular do banco de dados (conjunto de dados) com um hash específico.

Hora da prática

1/4 Execute o comando da lista de saldos e verifique se os balanços estão de acordo.

tbb saldos list

Saldos das contas em 7d4a360f465d...

| id | nome     | saldo   |
| -- | -------- | ------- |
| 1  | Andrej   | 999251  |
| 2  | BabaYaga | 949     | 
| 3  | Cesar    | 1000    |

2/4 Remova as 2 últimas filas de ./database/tx.db e verifique novamente os saldos.

tbb saldos list

Saldos das contas 841770dcd3...

| id | nome     | saldo   |
| -- | -------- | ------- |
| 1  | Andrej   | 999051  |
| 2  | BabaYaga | 949     | 
| 3  | Cesar    | 1000    |

3/4 Recompense Andrej pelos últimos 2 dias (de 28 a 30 de março):

Transação de recompensa 1:

tbb tx add --de=andrej --para=andrej --valor=100 --dado=recompensa

Persisting new TX to disk:
       {"de":"andrej","para":"andrej","valor":100,"dado":"recompensa"}
       
New DB Snapshot: ff2470c7043f5a34169b5dd38921ba6825b03b3facb83e426
TX persistida com sucesso no ledger.

Transação de recompensa 2:

tbb tx add --de=andrej --para=andrej --valor=100 --dado=recompensa

Persisting new TX to disk:
       {"from":"andrej","to":"andrej","value":100,"data":"reward"}
       
New DB Snapshot: 7d4a360f468b837b662816bcdc52c1869f99327d53ab4a9ca
TX persistida com sucesso no ledger.

4/4 Execute o comando da lista de saldos de tbb e garanta que os balanços e o hash do snapshot sejam os mesmos do início.

tbb saldos list

Saldos das contas em 7d4a360f465d...

| id | nome     | saldo   |
| -- | -------- | ------- |
| 1  | Andrej   | 999251  |
| 2  | BabaYaga | 949     | 
| 3  | Cesar    | 1000    |

Pronto!

Como a função criptográfica de hash sha256 produz a mesma saída (dadas as mesmas entradas, a tx.db atual e 2x tbb tx add), se você seguir os passos exatos em seu próprio computador, você gerará exatamente o mesmo estado e hashes do banco de dados!

Resumo:

O software fechado com acesso centralizado aos dados privados coloca apenas algumas poucas pessoas na posição de poder. Os usuários não têm escolha, e os acionistas estão no negócio para ganhar dinheiro.

Os desenvolvedores da blockchain visam desenvolver protocolos onde os empresários e usuários das aplicações se sinergizem em uma relação transparente e auditável. As especificações da blockchain devem ser bem definidas desde o início e só devem mudar se seus usuários o apoiarem.

A blockchain é um banco de dados imutável. O fornecimento de tokens, os saldos iniciais de usuários e as configurações globais da blockchain que você define em um arquivo Genesis. Os balanços Genesis indicam qual era o estado original da blockchain e nunca são atualizados depois.

As mudanças de estado do banco de dados são chamadas Transações (TX). Transações são eventos à moda antiga que representam ações dentro do sistema.

O conteúdo do banco de dados é passado por uma função de hash criptográfico segura. Os participantes da blockchain usam o hash resultante para referenciar um estado específico do banco de dados.

Código de estudo

Commit: b99e51

Próximos passos

Você terminou os primeiros capítulos! Parabéns!

█▒▒▒▒▒▒▒▒▒ 10%

Este, porém, foi apenas um aquecimento rápido. A blockchain é uma tecnologia muito desafiadora e extensa. Você precisaria de um livro inteiro explicando como construir o sistema completo e todos os seus componentes a partir do zero. Por isso, escrevi um.

Você pode continuar lendo o próximo capítulo gratuito no eBook com minha versão da newsletter "The Blockchain Way of Programming".

07 | O Modelo de programação da blockchain

  • Melhorando o desempenho de um BD imutável
  • Batch + Hash + Lista vinculadas ⇒ Blocos
  • Migrando de TX.db para BLOCKS.db

Aprendizagem: você redesenha e refatora seu banco de dados MVP e o transforma em uma arquitetura de blockchain.

Continuação do tutorial: https://web3.coach#book

Obrigado por leitura!