Os olhos têm medo, mas as mãos coçam!
Nos artigos anteriores, discutimos as tecnologias sobre as quais os blockchains são construídos () e os casos que podem ser realizados com sua ajuda (). É hora de colocar a mão na massa! Para a implementação de pilotos e PoC (Prova de Conceito), prefiro usar nuvens, pois têm acesso de qualquer lugar do mundo e, muitas vezes, não é necessário perder tempo na instalação tediosa do ambiente, pois existem configurações pré-instaladas. Então, vamos fazer algo simples, como uma rede para transferir moedas entre participantes, e chamá-la modestamente de CitCoin. Para isso, usaremos a nuvem da IBM e o blockchain universal Hyperledger Fabric. Primeiro, vamos entender por que o Hyperledger Fabric é chamado de blockchain universal?

Hyperledger Fabric — blockchain universal
De maneira geral, um sistema de informação universal é:
- Um conjunto de servidores e um núcleo de software que executa a lógica de negócios;
- Interfaces para interação com o sistema;
- Meios para registro, autenticação e autorização de dispositivos/pessoas;
- Um banco de dados que armazena dados operacionais e arquivados:

A versão oficial sobre o que é o Hyperledger Fabric pode ser lida em , e se formos resumir, o Hyperledger Fabric é uma plataforma de código aberto que permite construir blockchains privados e executar contratos inteligentes arbitrários, escritos nas linguagens de programação JS e Go. Vamos analisar detalhadamente a arquitetura do Hyperledger Fabric e nos certificar de que este é um sistema universal, que apenas possui especificidades na armazenagem e gravação de dados. A especificidade consiste no fato de que os dados, como em todos os blockchains, são armazenados em blocos, que são incluídos no blockchain somente se os participantes chegarem a um consenso, e uma vez gravados, os dados não podem ser modificados ou excluídos sem que isso seja percebido.
Arquitetura do Hyperledger Fabric
O diagrama apresenta a arquitetura do Hyperledger Fabric:

Organizações — as organizações contêm peers, assim, o blockchain existe graças ao suporte das organizações. Diferentes organizações podem fazer parte de um mesmo canal.
Canal — uma estrutura lógica que une peers em grupos, assim, define-se o blockchain. O Hyperledger Fabric pode processar simultaneamente vários blockchains com lógicas de negócios distintas.
Provedor de Serviços de Associados (MSP) — é a CA (Autoridade Certificadora) para a emissão de identidades e atribuição de funções. Para criar um nó, é necessário interagir com o MSP.
Nós pares — verificam transações, armazenam a blockchain, executam contratos inteligentes e interagem com aplicativos. Os pares possuem uma identidade (certificado digital) emitido pela MSP. Diferente da rede Bitcoin ou Ethereum, onde todos os nós têm igualdade de direitos, no Hyperledger Fabric, os nós desempenham diferentes papéis:
- Um par pode ser par endossante (EP) e executar contratos inteligentes.
- Par de compromisso (CP) — apenas armazenam dados na blockchain e atualizam o 'estado atual'.
- Par âncora (AP) — se várias organizações estão envolvidas na blockchain, os pares âncoras são usados para a comunicação entre elas. Cada organização deve ter um ou mais pares âncoras. Com o AP, qualquer par da organização pode obter informações sobre todos os pares em outras organizações. Para a sincronização de informações entre os AP, é utilizado o .
- Par líder — se uma organização tem vários pares, apenas o par líder receberá blocos do serviço de ordenação e os enviará aos outros pares. O líder pode ser definido staticamente ou selecionado dinamicamente pelos pares na organização. Para a sincronização de informações sobre os líderes, também é utilizado o protocolo de gossip.
Ativos — entidades que possuem valor, armazenadas na blockchain. Mais especificamente — são dados chave-valor no formato JSON. Esses dados são os que são gravados na 'Blockchain'. Eles têm um histórico que é mantido na blockchain e um estado atual que é mantido no banco de dados 'estado atual'. As estruturas de dados são preenchidas aleatoriamente, dependendo das necessidades empresariais. Não há campos obrigatórios, a única recomendação é que os ativos devem ter um proprietário e representar valor.
Livro razão — consiste na blockchain 'Blockchain' e no banco de dados 'Estado Atual', onde o estado atual dos ativos é armazenado. O estado atual utiliza LevelDB ou CouchDB.
Contrato inteligente — a lógica de negócios do sistema é implementada por meio de contratos inteligentes. No Hyperledger Fabric, os contratos inteligentes são chamados de chaincode. Através do chaincode, ativos e transações sobre eles são definidos. Em termos técnicos, contratos inteligentes são módulos de software implementados nas linguagens de programação JS ou Go.
Política de endosse — para cada chaincode, é possível definir políticas sobre quantos e de quem é necessário esperar confirmações para a transação. Se a política não for definida, o padrão utilizado é: “a transação deve ser confirmada por qualquer membro de qualquer organização no canal”. Exemplos de políticas:
- A transação deve ser confirmada por qualquer administrador da organização;
- Deve ser confirmado por qualquer membro ou cliente da organização;
- Deve ser confirmado por qualquer peer da organização.
Serviço de ordenação — empacota transações em blocos e os envia para peers no canal. Garante a entrega de mensagens a todos os peers na rede. Para sistemas industriais, utiliza-se , para desenvolvimento e teste .
CallFlow

- O aplicativo interage com o Hyperledger Fabric, usando Go, Node.js ou Java SDK;
- O cliente cria a transação tx e a envia para os peers de endorsement;
- O peer verifica a assinatura do cliente, executa a transação e envia a assinatura de endorsement de volta ao cliente. O chaincode é executado apenas nos peers de endorsement, e o resultado de sua execução é enviado a todos os peers. Esse algoritmo de funcionamento é chamado de — consenso PBFT (Practical Byzantine Fault Tolerant). Difere do no fato de que a mensagem é enviada e se espera a confirmação não de todos os participantes, mas apenas de um conjunto específico;
- Depois que o cliente recebe o número de respostas correspondente à política de endorsement, ele envia a transação para o serviço de ordenação;
- O serviço de ordenação forma um bloco e o envia para todos os peers de compromisso. O serviço de ordenação garante a gravação sequencial de blocos, o que exclui o chamado fork do ledger ();
- Os peers recebem o bloco, verificam novamente a política de endorsement, gravam o bloco na blockchain e alteram o estado no banco de dados 'World state'.
Ou seja, há uma separação de funções entre os nós. Isso facilita a escalabilidade e segurança da blockchain:
- Os smart contracts (chaincode) são executados pelos peers de endorsement. Isso garante a privacidade dos smart contracts, pois não são armazenados por todos os participantes, mas apenas nos peers de endorsement.
- A ordenação deve funcionar rapidamente. Isso é garantido porque a ordenação apenas forma o bloco e o envia para um conjunto fixo de peers líderes.
- Os peers de compromisso apenas armazenam a blockchain — podem ser muitos e não requerem grande potência nem trabalho instantâneo.
Para mais informações sobre as soluções arquitetônicas do Hyperledger Fabric e por que ele funciona dessa maneira, veja aqui: ou aqui: .
Portanto, o Hyperledger Fabric é realmente um sistema versátil que permite:
- Implementar lógica de negócios arbitrária usando o mecanismo de smart contracts;
- Gravar e recuperar dados do banco de dados blockchain no formato JSON;
- Fornecer e verificar acesso à API, utilizando a Autoridade Certificadora.
Agora que entendemos um pouco sobre as especificidades do Hyperledger Fabric, vamos finalmente fazer algo útil!
Implantando blockchain
Formulação do problema
A tarefa é implementar uma rede Citcoin com as seguintes funcionalidades: criar conta, obter saldo, recarregar conta, transferir moedas de uma conta para outra. Vamos desenhar o modelo de objeto, que será implementado no smart contract. Assim, teremos contas que se identificam por nomes (name) e contêm saldo (balance), além de uma lista de contas. Contas e listas de contas são, em termos de Hyperledger Fabric, ativos. Portanto, eles têm uma história e um estado atual. Tentarei ilustrar isso claramente:

As figuras superiores representam o estado atual, que é armazenado no estado do mundo ('World state'). Abaixo, as figuras mostram a história, que é armazenada na blockchain. O estado atual dos ativos muda por meio de transações. O ativo muda apenas como um todo, portanto, como resultado da transação, um novo objeto é criado e o valor atual do ativo é registrado na história.
Nuvem IBM
Criando uma conta na . Para usar a plataforma blockchain, é necessário atualizá-la para Pay-As-You-Go. Esse processo pode não ser rápido, pois a IBM solicita informações adicionais e as verifica manualmente. Por outro lado, posso dizer que a IBM tem bons materiais de aprendizado que permitem implantar o Hyperledger Fabric em sua nuvem. Gostei do seguinte ciclo de artigos e exemplos:
Abaixo estão capturas de tela da Plataforma Blockchain da IBM. Isso não é um guia para criar blockchain, mas apenas uma demonstração do escopo da tarefa. Assim, para nossos fins, criamos uma Organização:

Nela, criamos nós: Orderer CA, Org1 CA, Orderer Peer:

Criamos usuários:

Criamos um Canal e o chamamos de citcoin:

Na essência, o Canal é o blockchain, portanto, começa com o bloco zero (Bloco Gênesis):

Escrevemos o Smart Contract
/*
* Citcoin smart-contract v1.5 for Hyperledger Fabric
* (c) Alexey Sushkov, 2019
*/
'use strict';
const { Contract } = require('fabric-contract-api');
const maxAccounts = 5;
class CitcoinEvents extends Contract {
async instantiate(ctx) {
console.info('instantiate');
let emptyList = [];
await ctx.stub.putState('accounts', Buffer.from(JSON.stringify(emptyList)));
}
// Get all accounts
async GetAccounts(ctx) {
// Get account list:
let accounts = '{}'
let accountsData = await ctx.stub.getState('accounts');
if (accountsData) {
accounts = JSON.parse(accountsData.toString());
} else {
throw new Error('accounts not found');
}
return accountsData.toString()
}
// add a account object to the blockchain state identifited by their name
async AddAccount(ctx, name, balance) {
// this is account data:
let account = {
name: name,
balance: Number(balance),
type: 'account',
};
// create account:
await ctx.stub.putState(name, Buffer.from(JSON.stringify(account)));
// Add account to list:
let accountsData = await ctx.stub.getState('accounts');
if (accountsData) {
let accounts = JSON.parse(accountsData.toString());
if (accounts.length < maxAccounts)
{
accounts.push(name);
await ctx.stub.putState('accounts', Buffer.from(JSON.stringify(accounts)));
} else {
throw new Error('Max accounts number reached');
}
} else {
throw new Error('accounts not found');
}
// return object
return JSON.stringify(account);
}
// Sends money from Account to Account
async SendFrom(ctx, fromAccount, toAccount, value) {
// get Account from
let fromData = await ctx.stub.getState(fromAccount);
let from;
if (fromData) {
from = JSON.parse(fromData.toString());
if (from.type !== 'account') {
throw new Error('wrong from type');
}
} else {
throw new Error('Accout from not found');
}
// get Account to
let toData = await ctx.stub.getState(toAccount);
let to;
if (toData) {
to = JSON.parse(toData.toString());
if (to.type !== 'account') {
throw new Error('wrong to type');
}
} else {
throw new Error('Accout to not found');
}
// update the balances
if ((from.balance - Number(value)) >= 0 ) {
from.balance -= Number(value);
to.balance += Number(value);
} else {
throw new Error('From Account: not enought balance');
}
await ctx.stub.putState(from.name, Buffer.from(JSON.stringify(from)));
await ctx.stub.putState(to.name, Buffer.from(JSON.stringify(to)));
// define and set Event
let Event = {
type: "SendFrom",
from: from.name,
to: to.name,
balanceFrom: from.balance,
balanceTo: to.balance,
value: value
};
await ctx.stub.setEvent('SendFrom', Buffer.from(JSON.stringify(Event)));
// return to object
return JSON.stringify(from);
}
// get the state from key
async GetState(ctx, key) {
let data = await ctx.stub.getState(key);
let jsonData = JSON.parse(data.toString());
return JSON.stringify(jsonData);
}
// GetBalance
async GetBalance(ctx, accountName) {
let data = await ctx.stub.getState(accountName);
let jsonData = JSON.parse(data.toString());
return JSON.stringify(jsonData);
}
// Refill own balance
async RefillBalance(ctx, toAccount, value) {
// get Account to
let toData = await ctx.stub.getState(toAccount);
let to;
if (toData) {
to = JSON.parse(toData.toString());
if (to.type !== 'account') {
throw new Error('wrong to type');
}
} else {
throw new Error('Accout to not found');
}
// update the balance
to.balance += Number(value);
await ctx.stub.putState(to.name, Buffer.from(JSON.stringify(to)));
// define and set Event
let Event = {
type: "RefillBalance",
to: to.name,
balanceTo: to.balance,
value: value
};
await ctx.stub.setEvent('RefillBalance', Buffer.from(JSON.stringify(Event)));
// return to object
return JSON.stringify(from);
}
}
module.exports = CitcoinEvents;
Intuitivamente, tudo aqui deve ser claro:
- Existem várias funções (AddAccount, GetAccounts, SendFrom, GetBalance, RefillBalance), que serão chamadas pelo programa de demonstração usando a API do Hyperledger Fabric.
- As funções SendFrom e RefillBalance geram eventos (Event), que serão recebidos pelo programa de demonstração.
- A função instantiate é chamada uma vez ao instanciar o contrato inteligente. Na verdade, ela é chamada não uma vez, mas sempre que a versão do contrato inteligente é alterada. Portanto, inicializar a lista com um array vazio é uma má ideia, pois agora, ao mudar a versão do contrato inteligente, perderemos a lista atual. Mas tudo bem, estou apenas aprendendo).
- Os Accounts e a lista de accounts (accounts) são estruturas de dados JSON. JavaScript é utilizado para manipular os dados.
- O valor atual do asset pode ser obtido através da chamada da função getState e atualizado com putState.
- Ao criar um Account, a função AddAccount é chamada, onde é feita a comparação com o número máximo de accounts na blockchain (maxAccounts = 5). E aqui há um erro (notaram?), que leva ao crescimento infinito do número de accounts. Esses tipos de erros devem ser evitados)
Em seguida, carregamos o contrato inteligente no Channel e o instanciamos:

Observando a transação de instalação do Smart Contract:

Vejamos os detalhes sobre o nosso Channel:

Como resultado, obtemos o seguinte esquema da rede blockchain na nuvem IBM. Também no esquema está presente um programa de demonstração, executado na nuvem Amazon em um servidor virtual (detalhes sobre isso estarão na próxima seção):

Criando um GUI para chamadas da API do Hyperledger Fabric
O Hyperledger Fabric possui uma API que pode ser usada para:
- Criar channel;
- Conectar um peer ao channel;
- Instalar e instanciar contratos inteligentes no channel;
- Chamar transações;
- Solicitar informações na blockchain.
Desenvolvendo um aplicativo
Em nosso programa de demonstração, usaremos a API apenas para chamar transações e solicitar informações, pois já realizamos as outras etapas utilizando a plataforma de blockchain IBM. Estamos escrevendo o GUI, utilizando a pilha de tecnologias padrão: Express.js + Vue.js + Node.js. Como começar a criar aplicativos web modernos poderia resultar em um artigo separado. Aqui deixo um link para uma série de palestras que eu mais gostei: . O resultado foi um aplicativo cliente-servidor com uma interface gráfica familiar no estilo Material Design do Google. A API REST entre o cliente e o servidor consiste em várias chamadas:
- HyperledgerDemo/v1/init — inicializar a blockchain;
- HyperledgerDemo/v1/accounts/list — obter a lista de todas as accounts;
- HyperledgerDemo/v1/account?name=Bob&balance=100 — criar a account Bob;
- HyperledgerDemo/v1/info?account=Bob — obter informações sobre a account Bob;
- HyperledgerDemo/v1/transaction?from=Bob&to=Alice&volume=2 — transferir duas moedas de Bob para Alice;
- HyperledgerDemo/v1/disconnect — desconectar da blockchain.
Coloquei a descrição da API com exemplos em — um programa amplamente conhecido para testar APIs HTTP.
Aplicativo demo na nuvem Amazon
Enviei o aplicativo para a Amazon, pois a IBM ainda não conseguiu atualizar minha conta e permitir a criação de servidores virtuais. Como toque final, adicionei o domínio: . Vou manter um pouco o servidor ligado, depois desligarei, pois os centavos pela locação continuam a contar, e as moedas citcoin ainda não estão listadas na exchange) Coloco capturas de tela do demo no artigo para ilustrar a lógica de operação. O aplicativo demo pode:
- Inicializar a blockchain;
- Criar uma Conta (mas atualmente não é possível criar uma nova Conta, pois o número máximo de contas especificado no contrato inteligente foi alcançado);
- Obter a lista de Contas;
- Transferir moedas citcoin entre Alice, Bob e Alex;
- Obter eventos (mas atualmente não é possível mostrar eventos, portanto, a interface simplificada indica que eventos não são suportados);
- Registrar ações.
Primeiro, inicializamos a blockchain:

Depois, criamos nossa conta, sem economizar no saldo:

Obtemos a lista de todas as contas disponíveis:

Selecionamos o remetente e o destinatário, e obtemos seus saldos. Se o remetente e o destinatário forem os mesmos, ele fará um depósito em sua conta:

No log, acompanhamos a execução das transações:

Com isso, encerramos a demo do programa. A seguir, é possível visualizar nossa transação na blockchain:

E a lista geral de transações:

Assim, concluímos com sucesso a implementação do PoC para criar a rede Citcoin. O que mais precisamos fazer para que a Citcoin se torne uma rede completa para transferir moedas? Muito pouco:
- Na fase de criação da conta, implementar a geração de chave privada/pública. A chave privada deve ser armazenada pelo usuário da conta, enquanto a pública na blockchain.
- Realizar a transferência de moedas, na qual a identificação do usuário utiliza a chave pública em vez do nome.
- Criptografar as transações do usuário para o servidor com sua chave privada.
Conclusão
Implementamos a rede Citcoin com as funções: adicionar conta, obter saldo, recarregar sua conta, transferir moedas de uma conta para outra. Então, o que precisamos para construir o PoC?
- Precisamos estudar a blockchain em geral e o Hyperledger Fabric em particular;
- Aprender a usar as nuvens da IBM ou Amazon;
- Aprender a linguagem de programação JS e algum framework web;
- Se precisar armazenar certos dados não na blockchain, mas em um banco de dados separado, aprenda a integrar, por exemplo, com PostgreSQL;
- E por último, mas não menos importante — sem conhecimento de Linux, nos dias de hoje, não dá para ir longe!)
Claro, não é ciência de foguetes, mas vai dar trabalho!
Códigos-fonte no GitHub
Coloquei os fontes em . Breve descrição do repositório:
O diretório "servidor" — servidor Node.js
O diretório "client" — cliente Node.js
O diretório "blockchain" (os valores dos parâmetros e as chaves, claro, são fictícias e servem apenas como exemplo):
- contract — fonte do smart contract
- wallet — chaves do usuário para usar a API do Hyperledger Fabric.
- *.cds — versões compiladas dos smart contracts
- *.json arquivos — exemplos de arquivos de configuração para uso da API do Hyperledger Fabric
É apenas o começo!
Fonte: habr.com
