Como testar o hyperledger smart contract (chaincode) localmente em sua máquina?

Introdução

Nesse post, compartilho uma forma que entendi ser mais simples, para testar os chaincodes (smart contracts) do Hyperledger direto na sua máquina, sem depender de estruturas externas, pelo menos nos testes iniciais.

Motivação

Aprender a programar para o Hyperledger, mais especificamente para o mais renomado framework de blockchain permissionada (ou privada, como alguns atores costumam chamar) existente no mercado, que atualmente é mantido por algumas grandes empresas de tecnologia, sendo a IBM uma das principais, pode ser bastante complexo no início.

Comecei a aprender durante meu trabalho na Growth Tech (empresa que trabalho no momento que escrevo este post).

Quando se começa a pesquisar sem saber muito bem como testar tudo, chega-se a links complexos, como esse https://hyperledger-fabric.readthedocs.io/en/release-1.2/build_network.html#generate-network-artifacts.

Vendo links como esse acima, as coisas começaram a parecer que seriam complexas demais e, no final, não foram tão difíceis quanto eu esperava. Com esse post, pretendo simplificar esse processo e facilitar sua vida.

Pré requisitos

  • Para prosseguir nesse tutorial, idealmente você já deveria saber como codificar minimamente em GO e como a estrutura do Hyperledger funciona dentro dele. Caso não saiba e queira ir direto ao código, deixarei no final do artigo o código do chaincode básico para testes. 🙂
    • Nesse artigo não irei abordar o código do chaincode em si, pois o farei em futuros artigos.

ps: as dicas aqui presente eu sei que funcionam bem no Mac (onde testei) e no Linux. Honestamente, não posso garantir para o Windows.

Instalação da base

Para testar o chaincode localmente, iremos usar o dev mode. Normalmente o chaincode é iniciado e mantido pelos peers mas, no durante esse estágio de desenvolvimento e testes local, essa tarefa será do usuário. Isso deixará o processo de testes mais rápido.

Esse processo pede alguns passos para ser executado. Começaremos pela instalação dos exemplos, imagens do Docker, essas coisas. Vamos lá:

Primeiro, escolha um diretório aonde pretende deixar os códigos ligados à Blockchain. Esse diretório será a base da nossa instalação.

Rode esse código no terminal (não se preocupe, ele é parte do tutorial do site oficial da Hyperledger).

curl -sSL http://bit.ly/2ysbOFE | bash -s 1.2.1

Ele irá baixar e rodar um shell script que irá baixar todos os binários necessários e específicos para sua plataforma.

Após isso, iremos de fato rodar nosso teste.

Testando nosso chaincode

Para nosso código ficar visível dentro das etapas seguintes, ele precisa estar no diretório /chaincode que vem dentro do fabric-samples. Recomenda-se que cada chaincode tenha sua própria pasta. Digamos, por exemplo, que nosso chaincode seja para guardar registros de alunos de uma escola na blockchain e a pasta seja escola, no meu caso, os arquivos .go do chaincode estariam em: /Users/jonathan/blockchain/fabric-samples/chaincode/escola

Para executarmos nossos testes, precisaremos de 3 terminais abertos na pasta do chaincode-docker-devmode que também vem dentro do fabric-samples.

Irei usar o meu path de exemplo. Eu rodei os comandos acima dentro da pasta /Users/jonathan/blockchain, logo, meus 3 termimais precisam ficar abertos em: /Users/jonathan/blockchain/fabric-samples/chaincode-docker-devmode/

Terminal 1

No primeiro terminal, iremos iniciar a rede:

# as duas linhas comentadas abaixo nao sao obrigatorias, mas caso a ultima linha de algum erro em relacao ao docker, roda-as
# docker stop $(docker ps -q) 
# docker rm $(docker ps -aq)
docker-compose -f docker-compose-simple.yaml up

Esse terminal ficará “preso” mantendo a estrutura ativa durante todo o período de testes. Não iremos mexer mais nele.

Terminal 2

No segundo terminal será onde iremos dar o build e o start do nosso chaincode:

docker exec -it chaincode bash

Após rodar esse comando, esperamos ver algo como (onde o ‘código’ entre o @ e o : será provavelmente diferente do meu):

root@55fed073eff4:/opt/gopath/src/chaincode#

Agora, tudo dando certo, iremos dar um build e ver se nosso chaincode compila como esperado:

cd escola #pasta do nosso chaincode
go build

O comando go build identifica automaticamente o arquivo principal e ‘builda’ o projeto. Caso tudo esteja ok, ele irá sair do comando sem nenhum retorno, aí podemos ir para o comando seguinte. Já se houver erro, ele irá dizer qual é o erro em questão dentro do código go. Ajeite-o até estar ok e vá para a etapa abaixo.

Tudo ok no código? Então vamos rodá-lo na nossa rede:

CORE_PEER_ADDRESS=peer:7052 CORE_CHAINCODE_ID_NAME=escola:0 ./escola

A partir daqui esse terminal também ficará “preso” durante os testes. O Terminal 3 que será o mais “dinâmico”, onde rodaremos os nossos testes.

Terminal 3

Nesse terminal será onde de fato poderemos testar e ver os retornos do nosso chaincode 🙂

Então vamos lá, rode o seguinte comando para entrar no bash onde rodaremos o chaincode:

docker exec -it cli bash

Agora iremos instalar e instânciar o nosso chaincode no nosso peer de teste:

peer chaincode install -p chaincodedev/chaincode/escola -n escola -v 0
peer chaincode instantiate -n escola -v 0 -c '{"Args":[]}' -C myc

Esse comando indo ok, está tudo preparado para a parte principal, onde iremos chamar o nosso invoke e, de fato, rodar nossa lógica interna:

Não estranhe que o terminal irá “rodar muita coisa” a cada comando. O resultado esperado é o final dele, como deixarei comentado logo abaixo de cada chamada do invoke, mais especificamente o payload. Esse resultado que será enviado à nossa API ou qualquer serviço que criemos para fazer o meio de campo entre Aplicação principal e a Blockchain.

peer chaincode invoke -n escola -c '{"Args":["add_aluno", "0001", "Jonathan", "111222333", "Programador"]}' -C myc
# resultado esperado é algo assim:
# 2018-11-04 16:57:24.996 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 0a8 Chaincode invoke successful. result: status:200 payload:"id added successfully"

# onde o que nos interessa e será de fato retornado é o final:
# result: status:200 payload:"id added successfully"

peer chaincode invoke -n escola -c '{"Args":["get_aluno", "0001"]}' -C myc
# resultado esperado é algo assim:
# 2018-11-04 16:57:53.735 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 0a8 Chaincode invoke successful. result: status:200 payload:"{\"docType\":\"RegAluno\",\"id\":\"id0001\",\"name\":\"Jonathan\",\"doc\":\"111222333\",\"course\":\"Programador\"}"

# onde o que nos interessa e será de fato retornado é o final:
# result: status:200 payload:"{\"docType\":\"RegAluno\",\"id\":\"id0001\",\"name\":\"Jonathan\",\"doc\":\"111222333\",\"course\":\"Programador\"}"


# caso tenha erro, o resultado vem do mesmo jeito
# digamos que tentamos ler o aluno código 00012, que não existe
peer chaincode invoke -n escola -c '{"Args":["get_aluno", "00012"]}' -C myc
# resultado esperado é algo assim:
# Error: endorsement failure during invoke. chaincode result: status:500 message:"Id not found"
# onde o que nos interessa e será de fato retornado é o final:
# status:500 message:"Id not found"

Se tudo correu bem até aqui, teremos algo assim no terminal:

Terminal rodando nosso chaincode

Dicas e comentários

  • Sempre teste localmente antes de enviar algo para produção, pois erros de build o go build pega, erros de lógica ou de negócios não.
  • Para usar a blockchain na prática dentro da IBM Blockchain, independente da aplicação, recomendo criar uma API que servirá de meio de campo entre sua aplicação e a blockchain (dica essa vinda direto de um call com um cara muito fera da própria IBM!).
    • Recomendo usar o Node JS para isso, pois ele tem o melhor e mais estável SDK para comunicação atualmente.
    • Pretendo criar um post futuramente sobre como criar essa API de maneira simples e funcional.
  • Se você programa em Go, sabe que se pode ter vários arquivos .go e, desde que eles estejam na mesma estrutura, você pode chamar as funções de um no outro.
    • Nesse caso você também pode fazer isso. Digamos que na escola.go eu tivesse usando funções de um arquivo de valições validacoes.go. Ao por nosso código na rede como já feito acima, ele sozinho consegue identificar as relações e tudo funciona normalmente.
    • Na hora de enviar o código para a IBM Blockchain bastará enviar todos os arquivos.
  • Dica realmente útil para rodar esses códigos:
    • Não tente decorar tudo. Acho desnecessário ficar decorando todos os comandos que rodamos no terminal, até porque não é fácil.
      • Faça como eu: pegue os códigos desse arquivo, copie para algum lugar, ajeite os paths para sua realidade e, sempre que precisar, só copiar e colar no terminal.
      • Foque nas suas lógicas de negócio, mais especificamente no chaincode, ele que realmente importa! A ‘burocracia’ para testar pode ser simplesmente copiada e colada a cada teste.
  • Por mais que eu tenha tentado simplicar ao máximo, de nada adianta se você não testar isso por conta própria e na sua máquina.
    • -> https://gist.github.com/JonathanVeg/dda0bb342c5ed00e451a3992bfaeb5da (Código do arquivo aluno.go que usei nos exemplos).
    • Fiz o código e disponibilizei no gist do Github. Ele está bem simples. Sugiro algumas melhorias como forma de treinar:
      • Verificar se um ID de aluno já existe e dar erro caso sim na chamada da função de ADD.
      • Validar o documento enviado (podemos assumir que aluno é pessoa física e, logo, o documento precisa ser um CPF válido).

Futuramente

Esse post é o meu primeiro post real no meu blog (até tem um outro aqui, mas é mais de divulgação de um APP meu). A ideia, neste blog, é tentar pegar coisas que eu faço, especialmente as que senti mais dificuldade para começar, e tentar passar de uma maneira simplicada.

Esse post tem como ideia ser o primeiro de uma série, levemente fora de ordem:

  1. Introdução ao Hyperledger e IBM Blockchain;
  2. Criando seu primeiro chaincode básico;
  3. Como testar o chaincode localmente na sua máquina (esse post!);
  4. Criando sua conta e subindo seu código para a plataforma da IBM Blockchain;
  5. Como criar uma API básica em NodeJS usando o SDK oficial e disponibilizando endpoints para sua aplicação (web ou mobile) usar a blockchain sem precisar entender como ela funciona (divisão de responsabilidades entre as várias partes da aplicação).

Todos esses itens acima eu já fiz e, como iniciante no tema, passei por umas dificuldades em cada um deles. Então a ideia é tentar criar materiais em português para ajudar àqueles que também forem passar por esse caminho. Espero que gostem.

Qualquer feedback é extremamente bem vindo, como meu primeiro post sei que não está na formatação nem linguagem ideal, mas pretendo ir melhorando.

  • Escrito por Jonathan Silva, colaborador da Growth Tech.

Onde me achar:

Fontes: