Blockchain: ¿qué nos cuesta construir un PoC?

¡Los ojos temen, pero las manos pican!

En artículos anteriores, analizamos las tecnologías en las que se basan las blockchains (¿Qué nos cuesta construir un blockchain?) y los casos de uso que se pueden implementar con ellas (¿Qué nos cuesta construir un caso?). ¡Es hora de trabajar con las manos! Para implementar pilotos y PoC (Prueba de Concepto), prefiero usar nubes, ya que se puede acceder a ellas desde cualquier parte del mundo y, a menudo, no hay que perder tiempo en la tediosa instalación del entorno, ya que hay configuraciones preinstaladas. Así que, hagamos algo simple, como una red para transferir monedas entre participantes y la llamaremos modestamente Cbitcoin. Para ello, utilizaremos la nube de IBM y la blockchain universal Hyperledger Fabric. Primero, analicemos por qué se llama a Hyperledger Fabric una blockchain universal.

Blockchain: ¿qué nos cuesta construir un PoC?

Hyperledger Fabric — blockchain universal

Hablando en términos generales, un sistema de información universal es:

  • Un conjunto de servidores y un núcleo de software que ejecuta la lógica empresarial;
  • Interfaces para interactuar con el sistema;
  • Herramientas para registrar, autenticar y autorizar dispositivos/personas;
  • Una base de datos que almacena datos operativos y archivados:

Blockchain: ¿qué nos cuesta construir un PoC?

Se puede leer la versión oficial sobre qué es Hyperledger Fabric en el sitio web, y en resumen, Hyperledger Fabric es una plataforma de código abierto que permite construir blockchains privadas y ejecutar contratos inteligentes arbitrarios escritos en los lenguajes de programación JS y Go. Vamos a examinar detenidamente la arquitectura de Hyperledger Fabric y comprobar que es un sistema universal, en el que solo hay especificidades en el almacenamiento y registro de datos. La especificidad radica en que los datos, como en todas las blockchains, se almacenan en bloques que se añaden a la blockchain solo si los participantes llegan a un consenso y, una vez registrado, los datos no se pueden modificar o eliminar de forma discreta.

Arquitectura de Hyperledger Fabric

En el esquema se presenta la arquitectura de Hyperledger Fabric:

Blockchain: ¿qué nos cuesta construir un PoC?

Organizaciones — las organizaciones contienen nodos peer, por lo que la blockchain existe gracias al apoyo de las organizaciones. Diferentes organizaciones pueden formar parte de un mismo canal.

Channel — estructura lógica que agrupa nodos peer, definiendo así la blockchain. Hyperledger Fabric puede procesar múltiples blockchains simultáneamente con diferentes lógicas empresariales.

Proveedor de Servicios de Membresía (MSP) — es una CA (Autoridad de Certificación) para la emisión de identidades y asignación de roles. Para crear un nodo, es necesario interactuar con el MSP.

Nodos peer — verifican transacciones, almacenan la cadena de bloques, ejecutan contratos inteligentes e interactúan con aplicaciones. Los pares tienen una identidad (certificado digital) que emite el MSP. A diferencia de la red Bitcoin o Etherium, donde todos los nodos son iguales, en Hyperledger Fabric los nodos desempeñan diferentes roles:

  • Un par puede ser par de endorsos (EP) y ejecutar contratos inteligentes.
  • Par de compromiso (CP) — solo almacenan datos en la cadena de bloques y actualizan el 'Estado Mundial'.
  • Par de anclaje (AP) — si en la cadena de bloques participan varias organizaciones, los pares de anclaje se utilizan para la conexión entre ellas. Cada organización debe tener uno o más pares de anclaje. A través de un AP, cualquier par en la organización puede obtener información sobre todos los pares en otras organizaciones. Para la sincronización de información entre AP, se utiliza el protocolo de gossip.
  • Par líder — si una organización tiene varios pares, solo el par líder recibirá bloques del servicio de ordenamiento y los proporcionará a los demás pares. El líder puede ser designado de manera estática o elegirse dinámicamente entre los pares de la organización. Para la sincronización de la información sobre los líderes, también se utiliza el protocolo de gossip.

Activos — entidades que tienen valor, almacenadas en la cadena de bloques. Más concretamente, son datos clave-valor en formato JSON. Estos datos son los que se registran en la cadena de bloques 'Blockchain'. Tienen un historial que se almacena en la cadena de bloques y un estado actual que se almacena en la base de datos 'Estado Mundial'. Las estructuras de datos se llenan aleatoriamente dependiendo de las necesidades comerciales. No hay campos obligatorios, la única recomendación es que los activos deben tener un propietario y representar un valor.

Libro mayor — consiste en la cadena de bloques 'Blockchain' y la base de datos 'Estado Mundial', en la que se almacena el estado actual de los activos. El Estado Mundial utiliza LevelDB o CouchDB.

Contrato inteligente — mediante contratos inteligentes se implementa la lógica comercial del sistema. En Hyperledger Fabric, los contratos inteligentes se llaman chaincode. Con el chaincode se definen los activos y las transacciones sobre ellos. Hablando en términos técnicos, los contratos inteligentes son módulos de software implementados en lenguajes de programación como JS o Go.

Política de endorsement — para cada chaincode se pueden definir políticas sobre cuántas y de quién se necesitan confirmaciones para una transacción. Si no se define una política, se utiliza por defecto: “la transacción debe ser confirmada por cualquier miembro (member) de cualquier organización en el canal”. Ejemplos de políticas:

  • La transacción debe ser confirmada por cualquier administrador de la organización;
  • Cualquiera de los miembros (member) o clientes de la organización debe confirmarla;
  • Cualquiera de los peers de la organización debe confirmarla.

Servicio de ordenación — empaqueta las transacciones en bloques y las envía a los peers en el canal. Garantiza la entrega de mensajes a todos los peers en la red. Para sistemas industriales se utiliza el corredor de mensajes Kafka, para desarrollo y pruebas Solo.

CallFlow

Blockchain: ¿qué nos cuesta construir un PoC?

  • La aplicación interactúa con Hyperledger Fabric usando Go, Node.js o Java SDK;
  • El cliente crea la transacción tx y la envía a los peers de endorsement;
  • El peer verifica la firma del cliente, ejecuta la transacción y envía la firma de endorsement de vuelta al cliente. El chaincode se ejecuta solo en los peers de endorsement, y el resultado de su ejecución se distribuye a todos los peers. Este algoritmo de funcionamiento se llama — consenso PBFT (Practical Byzantine Fault Tolerant). Se diferencia de el BFT clásico en que el mensaje se distribuye y se espera la confirmación no de todos los participantes, sino solo de un conjunto específico;
  • Después de que el cliente ha recibido el número de respuestas que corresponde a la política de endorsement, envía la transacción al servicio de ordenación;
  • El servicio de ordenación forma un bloque y lo envía a todos los peers de commits. El servicio de ordenación asegura que los bloques se registren en secuencia, lo que excluye, lo que se llama, fork del libro mayor (ver sección "Forks");
  • Los peers reciben el bloque, verifican nuevamente la política de endorsement, registran el bloque en la cadena de bloques y cambian el estado en la base de datos "World state".

Es decir, se produce una separación de roles entre los nodos. Esto asegura la escalabilidad y la seguridad de la cadena de bloques:

  • Los contratos inteligentes (chaincode) son ejecutados por los peers de endorsement. Esto asegura la confidencialidad de los contratos inteligentes, ya que no se almacenan en todos los participantes, sino únicamente en los peers de endorsement.
  • El servicio de ordenación debe funcionar rápidamente. Esto se logra porque el servicio de ordenación solo forma bloques y los envía a un conjunto fijo de peers líderes.
  • Los peers de commits solo almacenan la cadena de bloques; puede haber muchos de ellos y no requieren gran potencia ni un funcionamiento instantáneo.

Más sobre las decisiones arquitectónicas de Hyperledger Fabric y por qué funciona así se puede ver aquí: Orígenes de la Arquitectura o aquí: Hyperledger Fabric: Un Sistema Operativo Distribuido para Cadenas de Bloques Con Permiso.

Así que, Hyperledger Fabric es realmente un sistema universal, con el cual se puede:

  • Implementar cualquier lógica empresarial utilizando el mecanismo de contratos inteligentes;
  • Registrar y obtener datos de la base de datos blockchain en formato JSON;
  • Proporcionar y verificar el acceso a la API utilizando una Autoridad de Certificación.

Ahora que tenemos un poco más claro el funcionamiento de Hyperledger Fabric, ¡hagamos finalmente algo útil!

Desplegando blockchain

Planteamiento del problema

La tarea es implementar una red de Citcoin con las siguientes funciones: crear una cuenta, obtener el saldo, recargar la cuenta, transferir monedas de una cuenta a otra. Dibujaremos un modelo de objeto que luego implementaremos en un contrato inteligente. Así que tendremos cuentas que se identifican por nombres (name) y contienen saldo (balance), así como una lista de cuentas. Las cuentas y la lista de cuentas son, en términos de Hyperledger Fabric, activos (assets). Por lo tanto, tienen un historial y un estado actual. Intentaré representarlo visualmente:

Blockchain: ¿qué nos cuesta construir un PoC?

Las figuras superiores representan el estado actual, que se almacena en la base de 'World state'. Debajo de ellas, las figuras que muestran la historia, que se almacena en la blockchain. El estado actual de los activos se modifica mediante transacciones. El activo solo se modifica completamente, por lo que el resultado de la transacción crea un nuevo objeto y el valor actual del activo se entrega a la historia.

IBM Cloud

Creamos una cuenta en IBM Cloud. Para utilizar la plataforma blockchain, debe actualizarse a Pay-As-You-Go. Este proceso puede no ser rápido, ya que IBM solicita información adicional y la verifica manualmente. Lo positivo es que IBM tiene buenos materiales de aprendizaje que permiten desplegar Hyperledger Fabric en su nube. Me gustó el siguiente ciclo de artículos y ejemplos:

A continuación, se presentan capturas de pantalla de la Plataforma Blockchain de IBM. No es una guía para crear un blockchain, sino simplemente una demostración del alcance de la tarea. Así que, para nuestros fines, creamos una Organización:

Blockchain: ¿qué nos cuesta construir un PoC?

En ella creamos nodos: Orderer CA, Org1 CA, Orderer Peer:

Blockchain: ¿qué nos cuesta construir un PoC?

Creamos usuarios:

Blockchain: ¿qué nos cuesta construir un PoC?

Creamos un Canal y lo llamamos citcoin:

Blockchain: ¿qué nos cuesta construir un PoC?

En esencia, el Canal es un blockchain, por lo que empieza con el bloque cero (Genesis block):

Blockchain: ¿qué nos cuesta construir un PoC?

Escribimos un 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, aquí debe quedar todo claro:

  • Hay varias funciones (AddAccount, GetAccounts, SendFrom, GetBalance, RefillBalance) que serán llamadas por un programa de demostración utilizando la API de Hyperledger Fabric.
  • Las funciones SendFrom y RefillBalance generan eventos (Event) que recibirá el programa de demostración.
  • La función instantiate se llama una vez al instanciar un contrato inteligente. En realidad, se llama no una vez, sino cada vez que se cambia la versión del contrato inteligente. Por lo tanto, inicializar la lista con un array vacío es una mala idea, ya que ahora, al cambiar la versión del contrato inteligente, perderemos la lista actual. Pero no se preocupen, ¡solo estoy aprendiendo!).
  • Las cuentas y la lista de cuentas son estructuras de datos en JSON. Para manipular estos datos se utiliza JS.
  • Se puede obtener el valor actual del activo mediante la llamada a la función getState, y actualizarlo con putState.
  • Al crear una cuenta, se llama a la función AddAccount, donde se realiza una comparación con el máximo número de cuentas en la blockchain (maxAccounts = 5). Y aquí hay un error (¿lo notaron?), que lleva a un crecimiento infinito del número de cuentas. Este tipo de errores deben evitarse).

A continuación, cargamos el contrato inteligente en el Canal y lo instanciamos:

Blockchain: ¿qué nos cuesta construir un PoC?

Vemos la transacción para la instalación del Smart Contract:

Blockchain: ¿qué nos cuesta construir un PoC?

Vemos los detalles de nuestro Canal:

Blockchain: ¿qué nos cuesta construir un PoC?

Como resultado, obtenemos el siguiente esquema de red blockchain en la nube de IBM. También en el esquema hay un programa demo que se ejecuta en la nube de Amazon en un servidor virtual (hablaremos de eso en la siguiente sección):

Blockchain: ¿qué nos cuesta construir un PoC?

Creación de GUI para llamadas a API de Hyperledger Fabric

Hyperledger Fabric tiene una API que se puede usar para:

  • Crear canales;
  • Conectar un nodo al canal;
  • Instalar e instanciar contratos inteligentes en el canal;
  • Llamar a transacciones;
  • Solicitar información en la blockchain.

Desarrollo de la aplicación

En nuestro programa demo, usaremos la API solo para llamar a transacciones y solicitar información, ya que ya hemos realizado los otros pasos utilizando la plataforma de blockchain de IBM. Escribimos la GUI usando el stack tecnológico estándar: Express.js + Vue.js + Node.js. Se podría escribir un artículo separado sobre cómo empezar a crear aplicaciones web modernas. Aquí dejo un enlace a una serie de conferencias que más me gustaron: Full Stack Web App using Vue.js & Express.js. Como resultado, se logró una aplicación cliente-servidor con una interfaz gráfica familiar en el estilo Material Design de Google. La REST API entre el cliente y el servidor consta de varias llamadas:

  • HyperledgerDemo/v1/init — inicializar la blockchain;
  • HyperledgerDemo/v1/accounts/list — obtener la lista de todas las cuentas;
  • HyperledgerDemo/v1/account?name=Bob&balance=100 — crear la cuenta Bob;
  • HyperledgerDemo/v1/info?account=Bob — obtener información sobre la cuenta Bob;
  • HyperledgerDemo/v1/transaction?from=Bob&to=Alice&volume=2 — transferir dos monedas de Bob a Alice;
  • HyperledgerDemo/v1/disconnect — cerrar la conexión con la blockchain.

He puesto la descripción de la API con ejemplos en el sitio «Postman» — un programa ampliamente conocido para probar APIs HTTP.

Aplicación de demostración en la nube de Amazon

Subí la aplicación a Amazon, ya que IBM todavía no ha podido actualizar mi cuenta y permitir la creación de servidores virtuales. Como una cereza en el pastel, añadí el dominio: www.citcoin.info. Mantendré un poco el servidor encendido, luego lo apagaré, ya que los centavos por el alquiler continúan acumulándose, y las monedas citcoin todavía no se cotizan en el intercambio) Coloco capturas de pantalla de la demostración en el artículo para que se entienda la lógica de funcionamiento. La aplicación de demostración puede:

  • Inicializar la blockchain;
  • Crear cuentas (pero ahora no se puede crear una nueva cuenta, ya que se ha alcanzado el número máximo de cuentas permitido en el contrato inteligente);
  • Obtener la lista de cuentas;
  • Transferir monedas citcoin entre Alice, Bob y Alex;
  • Obtener eventos (pero actualmente no se pueden mostrar eventos, por lo que en la interfaz por simplicidad se indica que los eventos no se soportan);
  • Registrar acciones.

Primero inicializamos la blockchain:

Blockchain: ¿qué nos cuesta construir un PoC?

Luego creamos nuestra cuenta, no escatimamos en el saldo:

Blockchain: ¿qué nos cuesta construir un PoC?

Obtenemos la lista de todas las cuentas disponibles:

Blockchain: ¿qué nos cuesta construir un PoC?

Elegimos al remitente y al destinatario, obtenemos sus saldos. Si el remitente y el destinatario son la misma persona, se recargará su cuenta:

Blockchain: ¿qué nos cuesta construir un PoC?

En el registro seguimos la ejecución de las transacciones:

Blockchain: ¿qué nos cuesta construir un PoC?

Con esto, en realidad, concluye la demostración del programa. A continuación, podemos ver nuestra transacción en la blockchain:

Blockchain: ¿qué nos cuesta construir un PoC?

Y la lista completa de transacciones:

Blockchain: ¿qué nos cuesta construir un PoC?

Así hemos finalizado con éxito la implementación del PoC para la creación de la red Citcoin. ¿Qué más se necesita para que Citcoin se convierta en una red completa para transferir monedas? Muy poco:

  • En la etapa de creación de la cuenta, implementar la generación de clave privada/publica. La clave privada debe ser almacenada por el usuario de la cuenta, la pública en la blockchain.
  • Realizar la transferencia de monedas, en la que se utiliza la clave pública en lugar del nombre para identificar al usuario.
  • Cifrar las transacciones que van del usuario al servidor con su clave privada.

Conclusión

Hemos implementado la red Citcoin con funciones: añadir cuenta, obtener saldo, recargar su cuenta, transferir monedas de una cuenta a otra. Entonces, ¿qué nos costó construir este PoC?

  • Es necesario estudiar la blockchain en general y Hyperledger Fabric en particular;
  • Aprender a utilizar los servicios en la nube de IBM o Amazon;
  • Aprender el lenguaje de programación JS y algún framework web;
  • Si se necesitan almacenar ciertos datos no en la cadena de bloques, sino en una base de datos separada, hay que aprender a integrarse, por ejemplo, con PostgreSQL;
  • Y lo último en la lista, pero no menos importante: ¡sin conocimientos de Linux en el mundo moderno no vamos a ninguna parte!)

Por supuesto, no es ciencia espacial, ¡pero habrá que esforzarse!

Códigos fuente en GitHub

He colocado los archivos fuente en GitHub. Descripción breve del repositorio:
El directorio «servidor» — el servidor de Node.js
El directorio «client» — el cliente de Node.js
El directorio «blockchain» (los valores de los parámetros y las claves, por supuesto, no funcionan y se proporcionan solo como ejemplo):

  • contract — el código fuente del contrato inteligente
  • wallet — las claves del usuario para usar la API de Hyperledger Fabric.
  • *.cds — versiones compiladas de contratos inteligentes
  • *.json archivos — ejemplos de archivos de configuración para usar la API de Hyperledger Fabric

¡Esto es solo el principio!

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster