Back-End

12 mai, 2017

Blockchain chaincode para desenvolvedores Java – parte 02

Publicidade

Na primeira parte deste artigo, você se familiarizou com o como criar, executar, implantar e invocar o chaincode, mas ainda não escreveu nenhum código Java.

Nesta seção, você usará o Eclipse IDE, um plugin para Gradle que funciona com Eclipse e um esqueleto do projeto chaincode Java chamado ChaincodeTutorial para escrever seu primeiro chaincode em Java. Você obterá o código esqueleto de um repositório GitHub que criei para este tutorial, importará esse código para o Eclipse, adicionará código para tornar a função de contrato inteligente em chaincode de acordo com os requisitos e criará esse código usando o Gradle dentro do seu Eclipse IDE.

Escreva o seu primeiro programa chaincode Java

Aqui estão os passos que você irá seguir:

  1. Instale o plugin Gradle Buildship para Eclipse.
  2. Clone o projeto ChaincodeTutorial do GitHub.
  3. Importe o projeto para o Eclipse.
  4. Explore o projeto esqueleto do chaincode.
  5. Escreva o chaincode Java.
  6. Compile o chaincode Java.

Quando tiver concluído esta seção, o seu chaincode estará pronto para ser executado na sua rede local blockchain.

1. Instale o plugin Gradle Buildship para Eclipse

Você pode usar qualquer IDE que você quiser, mas as instruções neste tutorial são para Eclipse. Nota: O plugin Buildship Gradle ajuda a integrar Gradle com Eclipse, mas você ainda precisará ter instalado o Gradle no seu computador.

Se você estiver nos acompanhando neste tutorial, você já deve ter Gradle instalado em seu computador; se não estiver instalado, faça isso agora.

Para instalar o plugin Buildship Gradle para Eclipse, que ajuda a sua instalação Gradle a trabalhar/funcionar com Eclipse, no Eclipse, vá para Ajuda > Eclipse Marketplace… Na caixa de diálogo Eclipse Marketplace, digite buildship no campo de texto Find e clique no botão Go. Você deve ver algo como na Figura 1, mostrando o plugin Integration 2.0 Buildache Gradle como o primeiro resultado da pesquisa:

Figura 1. Eclipse Marketplace: plugin Gradle Buildship

Em Integração Buildship Gradle, clique no botão Instalar e siga as instruções. Quando você clicar em Concluir, o plugin Buildship Gradle para Eclipse será instalado e você será solicitado a reiniciar Eclipse.

Quando o Eclipse reabrir, Gradle deve ser totalmente integrado com o seu Eclipse IDE. Agora você está pronto para clonar o repositório ChaincodeTutorial do GitHub.

2. Clonar o projeto ChaincodeTutorial do GitHub

Agora que você tem seu Eclipse IDE configurado para trabalhar com o Gradle, você clonará o código ChaincodeTutorial do GitHub e importará o código para Eclipse. Abra um prompt de comando ou janela de terminal, navegue até o seu $GOPATH e execute este comando:

git clone https://github.com/makotogo/ChaincodeTutorial.git

Seu resultado de comando deve se parecer como isto:

$ export GOPATH=/Users/sperry/home/mychaincode
$ cd $GOPATH
$ git clone https://github.com/makotogo/ChaincodeTutorial.git
Cloning into 'ChaincodeTutorial'...
remote: Counting objects: 133, done.
remote: Compressing objects: 100% (90/90), done.
remote: Total 133 (delta 16), reused 118 (delta 1), pack-reused 0
Receiving objects: 100% (133/133), 9.39 MiB | 1.95 MiB/s, done.
Resolving deltas: 100% (16/16), done.
$ cd ChaincodeTutorial
$ pwd
/Users/sperry/home/mychaincode/ChaincodeTutorial

Este comando clona o repositório Blockchain ChaincodeTutorial do GitHub para o seu $GOPATH. Ele consiste em um projeto esqueleto do chaincode Java com o qual você pode construir, executar e experimentar em sua rede local blockchain.

Mas antes que você possa fazer qualquer coisa, você precisa importar o código para o Eclipse.

3. Importe o projeto para o Eclipse

No Eclipse, vá para Arquivo > Importar…> Gradle> projeto Gradle Existente. Uma caixa de diálogo do assistente deverá abrir (veja a Figura 2).

Figura 2. Assistente de Importação do Eclipse: Projeto Gradle

Clique em Avançar. Na caixa de diálogo que aparece no assistente (veja a Figura 3), navegue até $GOPATH/ChaincodeTutorial e clique em Concluir para importar o projeto.

Figura 3. Assistente de Importação do Eclipse: Projeto Gradle (Diretório raiz do projeto)

Quando o projeto terminar de importar, certifique-se de selecionar Java Perspective e o projeto ChaincodeTutorial que você acabou de importar aparecerá na visualização do Project Explorer.

Agora que você tem o código importado em seu espaço de trabalho do Eclipse, você está pronto para escrever o seu chaincode.

4. Explore o esqueleto do projeto do chaincode

Nesta seção, você vai explorar o projeto chaincode para que entenda como ele deve funcionar, antes de escrever qualquer código Java.

Como desenvolvedores, adoramos escrever código, então eu não quero privá-lo da oportunidade de escrever código Java. No entanto, a configuração do projeto pode ser complexa, e eu não quero que isso seja uma pedra no caminho do objetivo principal deste tutorial. Para isso, forneci a maior parte do código que você precisará.

Antes de iniciarmos, vamos dar uma rápida olhada na classe base, chamada AbstractChaincode, que está localizada no pacote com.makotojava.learn.blockchain.chaincode e mostrada na Listagem 1.

Listagem 1. Classe AbstractChaincode

package com.makotojava.learn.blockchain.chaincode;
 
import java.util.Arrays;
 
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperledger.java.shim.ChaincodeBase;
import org.hyperledger.java.shim.ChaincodeStub;
 
public abstract class AbstractChaincode extends ChaincodeBase {
 
  private static final Log log = LogFactory.getLog(AbstractChaincode.class);
 
  public static final String FUNCTION_INIT = "init";
  public static final String FUNCTION_QUERY = "query";
 
  protected abstract String handleInit(ChaincodeStub stub, String[] args);
  protected abstract String handleQuery(ChaincodeStub stub, String[] args);
  protected abstract String handleOther(ChaincodeStub stub, String function, String[] args);
 
  @Override
  public String run(ChaincodeStub stub, String function, String[] args) {
    String ret;
    log.info("Greetings from run(): function -> " + function + " | args -> " + Arrays.toString(args));
    switch (function) {
    case FUNCTION_INIT:
      ret = handleInit(stub, args);
      break;
    case FUNCTION_QUERY:
      ret = handleQuery(stub, args);
    default:
      ret = handleOther(stub, function, args);
      break;
    }
    return ret;
  }
 
  @Override
  public String query(ChaincodeStub stub, String function, String[] args) {
    return handleQuery(stub, args);
  }
 
}

A primeira coisa que quero ressaltar é que o AbstractChaincode é uma subclasse de ChaincodeBase, que vem do cliente shim fabric (linhas 7, 10).

As linhas 17-19 mostram os métodos que você precisa implementar na classe ChaincodeLog (que é uma subclasse de AbstractChaincode) para lidar com as funções de inicialização, consulta de ledger e log, respectivamente.

As linhas 22-36 mostram o método run () da classe ChaincodeBase (a partir do cliente shim chaincode), onde descobrimos qual função foi invocada e para qual manipulador a chamada deve ser delegada. A classe é extensível, de modo que quaisquer outras funções que não init e query (como a função log) são tratadas pelo handleOther(), que você também deve implementar.

Agora, abra a classe ChaincodeLog no pacote com.makotojava.learn.blockchain.chaincode.

Eu forneci apenas um esqueleto para que você possa dar corpo – isto é, forneci código suficiente para que ele compile. Você terá que escrever o resto do código. Você deve executar os testes JUnit e ver que eles falham (porque você ainda não escreveu a implementação), e por qual motivo isso acontece. Em outras palavras, você pode usar os testes JUnit como um guia para implementar corretamente o código.

Agora, se isto dói um pouco sua cabeça, não se preocupe; eu forneci a solução, que está localizada em com.makotojava.learn.blockchain.chaincode.solution, no caso de você ficar preso (ou se você quiser apenas uma referência para guiá-lo através da implementação).

5. Escreva o chaincode Java

Primeiro, um pouco de base sobre o que você precisa saber para implementar os métodos chaincode em ChaincodeLog. A classe ChaincodeStub é como o seu chaincode Java se comunica com o framework Hyperledger Fabric, lembrando que o ledger está no centro da característica de transparência da tecnologia blockchain. O que faz com que um contrato inteligente (responsabilidade) funcione é o estado do ledger, e seu chaincode acessa o estado do ledger através do ChaincodeStub. Ao acessar o estado do ledger, você é capaz de implementar um contrato inteligente (ou seja, o chaincode).

Existem vários métodos no ChaincodeStub que permitem a você armazenar, recuperar e remover itens do estado atual do ledger, mas vou limitar nossa discussão neste tutorial a dois métodos, que armazenam e recuperam o estado do ledger:

  • putState (String key, String value) – Armazena o valor de estado especificado no ledger, mapeado de acordo com a chave especificada.
  • getState() – Obtém o valor de estado associado à chave especificada e retorna-o como String

Ao escrever o código para este tutorial, você usará as funções putState() e getState() sempre que precisar armazenar ou recuperar valores de estado do ledger, respectivamente. A classe ChaincodeLog somente armazena e recupera valores do ledger para implementar seu contrato inteligente, então isso é tudo o que você precisa saber para implementar os métodos. Mais chaincode complicado faria uso de alguns dos outros métodos em ChaincodeStub (mas esses também estão além do escopo deste tutorial).

Eu sou um grande fã de test-driven development  (TDD), então no modo TDD, eu escrevi os testes de unidade primeiro. Vá em frente, execute-os e veja-os falhar. Depois disso, você vai escrever código que segue as especificações até que os unit tests passem. O trabalho dos unit tests é garantir o comportamento esperado e, ao estuda-los, você deve ter informações suficientes para implementar os métodos.

No entanto, eu também escrevi comentários javadoc no topo de cada método que pode ajudar (no caso de você ser novo em TDD ou JUnit). Entre o código nos testes JUnit e os comentários javadoc no esqueleto ChaincodeLog, você deve ter tudo o que precisa para implementar o chaincode depois de concluir esta seção do tutorial.

Na visualização do Project Explorer (no Java Perspective), navegue até a classe ChaincodeLogTest, clique com o botão direito do mouse sobre ela e escolha Executar como > Teste Gradle. Quando ela é executada, você deve ver algo como a Figura 04, mostrando a árvore de todas as tarefas de Gradle que foram executadas. As tarefas concluídas com êxito são indicadas com marcas de verificação ao lado.

 

Figura 04. Eclipse: Exibição de Execuções Gradle

Os ícones de exclamação na guia Execuções de Gradle indicam as tarefas de Gradle correspondentes aos testes de unidade que falharam (existem quatro e todos falharam, tal como esperávamos).

Devido à maneira que eu escrevi os casos de teste JUnit, cada método de teste corresponde a um método em ChaincodeLog que você terá que implementar corretamente como parte deste tutorial.

Implemente getChaincodeID()

Primeiro, você precisa implementar getChaincodeID(). Seu contrato é para retornar o identificador exclusivo para o seu chaincode. Eu defini uma constante chamada CHAINCODE_ID na parte superior da classe ChaincodeLog que você deve usar. Sinta-se livre para alterar seu valor, mas se você alterar o chaincode id retornado por getChaincodeID(), certifique-se de que ele é exclusivo em sua rede e não se esqueça de alterar o atributo ChaincodeID.name de suas mensagens JSON também.

/**
 * Returns the unique chaincode ID for this chaincode program.
 */
@Override
public String getChaincodeID() {
  return null;// ADD YOUR CODE HERE
}

Exercício: Complete o método getChaincodeID(). Se você precisar de uma referência, procure no pacote com.makotojava.learn.blockchain.chaincode.solution.

Implemente handleInit()

Em seguida, implemente o método handleInit(). Seu contrato é para lidar com a inicialização do seu programa chaincode, que neste caso significa que ele irá adicionar uma mensagem (especificada pelo chamador) para o ledger e retornar essa mensagem para o chamador se a chamada for bem-sucedida.

/**
 * Handles initializing this chaincode program.
 *
 * Caller expects this method to:
 *
 * 1. Use args[0] as the key for logging.
 * 2. Use args[1] as the log message.
 * 3. Return the logged message.
 */
@Override
protected String handleInit(ChaincodeStub stub, String[] args) {
  return null;// ADD YOUR CODE HERE
}

Exercício: Complete o método handieInit(). Se você precisar de uma referência, procure no pacote com.makotojava.learn.blockchain.chaincode.solution.

Implemente handleQuery ()

A seguir está o método handleQuery (). Seu contrato é consultar o ledger, o que ele faz tomando a(s) chave(s) especificada(s), consultando o ledger para o(s) valor(es) que corresponde(m) a(s) chave(s), e retornando o(s) valor(es) para o chamador. Se várias chaves forem especificadas, os valores retornados devem ser separados por vírgulas.

/**
 * Handles querying the ledger.
 *
 * Caller expects this method to:
 * 
 * 1. Use args[0] as the key for ledger query.
 * 2. Return the ledger value matching the specified key
 *    (which should be the message that was logged using that key).
 */
@Override
protected String handleQuery(ChaincodeStub stub, String[] args) {
  return null;// ADD YOUR CODE HERE
}

Certifique-se de escrever código para a saída dos resultados da chamada de consulta, para que você possa ver os resultados na saída do console (dê uma olhada na solução se você quiser ver como eu fiz isso).

Exercício: Complete o método handleQuery(). Se você precisar de uma referência, procure no pacote com.makotojava.learn.blockchain.chaincode.solution.

Implemente handleOther ()

Finalmente, você precisa implementar o método handleOther(), cujo contrato é lidar com outras mensagens (que é bastante aberto, mas é por isso mesmo extensível). Isto é onde você irá implementar a função log, cujo contrato é adicionar uma mensagem especificada pelo chamador para o ledger e retornar essa mensagem para o chamador se a chamada foi bem-sucedida. Isso parece muito semelhante ao que acontece na função init, então talvez você possa aproveitar isso em sua implementação.

/**
 * Handles other methods applied to the ledger.
 * Currently, that functionality is limited to these functions:
 * - log
 *
 * Caller expects this method to:
 * Use args[0] as the key for logging.
 * Use args[1] as the log message.
 * Return the logged message.
 */
@Override
protected String handleOther(ChaincodeStub stub, String function, String[] args) {
  // TODO Auto-generated method stub
  return null;// ADD YOUR CODE HERE
}

Exercício: Complete o método handleOther(). Se você precisar de uma referência, procure no pacote com.makotojava.learn.blockchain.chaincode.solution.

Se o código que você escreveu para cada um dos exercícios anteriores atende aos requisitos conforme os estabeleci nesta seção (e nos comentários de código), então seus testes JUnit devem passar e o seu chaincode deve funcionar bem quando ele estiver implantado e em execução em sua rede local blockchain.

Lembre-se, eu forneci uma solução no caso de você ficar preso (mas você deve a si mesmo tentar implementar os métodos por conta própria antes de espreitar a solução).

6. Criar o chaincode Java

Agora que você escreveu o seu chaincode Java e todos os seus testes JUnit passam, é hora de você construir o seu chaincode usando o Eclipse e o plugin Gradle Buildship para o Eclipse. Puxe a visualização Gradle Tasks indo para Janela > Mostrar Visualização > Outros… então, procure gradle, selecione Tarefas Gradle e clique em OK. (Veja Figura 05.)

Figura 05. Eclipse > Exibir Visualização > visualização Tarefas Gradle

Quando a visualização Tarefas Gradle abrir, expanda o Chaincode Tutorial > node de construção e selecione construir e limpar. (Veja Figura 06.)

Figura 06. Eclipse: Visualização Tarefas Gradle

Clique com o botão direito do mouse em construir e limpar, então escolha Executar Tarefas Gradle (Gradle irá descobrir a ordem correta para executá-los). Sua visualização de Execuções Gradle deve mostrar uma compilação limpa, como mostrado na Figura 07, onde você tem apenas marcas de seleção ao lado de cada item.

Figura 07. Eclipse > visualização de Execuções Gradle > construção limpa

Quando a compilação terminar, você deve ter um diretório imediatamente subordinado ao seu diretório $GOPATH/ChaincodeTutorial (onde você clonou o código do GitHub anteriormente) chamado build/distributions que contém o seu chaincode (isso deveria parecer familiar, como você fez isso anteriormente no tutorial para o exemplo hello).

Agora que você construiu o seu chaincode Java, você está pronto para implantar, executar e invocar transações nele em sua rede local blockchain.

Faremos isso na terceira e última parte deste tutorial. Até lá.

***

Steve Perry faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela Redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: https://www.ibm.com/developerworks/library/j-chaincode-for-java-developers/index.html