Modelos de negocio de pago por uso en la industria. Primeros pasos con el protocolo blockchain EOSIO

En la cuarta revolución industrial, los modelos de negocio existentes se están poniendo patas arriba. Así, quienes desean seguir teniendo éxito deben mantener el pulso con la ayuda de las nuevas tecnologías y encontrar nuevos modelos de negocio para ellos. Los proveedores de la nube más conocidos, como Azure y AWS, ya están familiarizados con los modelos de negocio basados en los servicios, como el pago por uso (en inglés, «pay-per-use»). En el entorno industrial, si las máquinas y sus componentes se consideran una composición dinámica y no estática, es posible establecer paralelismos con la nube. A su vez, como todos los componentes de una fábrica están interconectados, es muy importante establecer una plataforma interoperable y neutra en lo que al fabricante se refiere, no solo para establecer la comunicación entre los componentes, sino también para garantizar un almacenamiento seguro de los datos. Y es aquí donde entra en juego el protocolo blockchain.

En esta entrada del blog, hablaremos de cómo utilizar el protocolo blockchain EOSIO para incorporar un prototipo para la facturación de servicios por uso en un entorno industrial.

El caso práctico concreto

En el modelo de negocio de pago por uso, los operarios de máquinas ya no compran las máquinas al fabricante, sino que solo pagan por el uso real que hacen de ellas. Esto supone diversas ventajas, tanto para el operario como para el fabricante. 1

El abanico de prestaciones puede abarcar desde el simple giro de un motor hasta un complejo servicio digital. Ahora bien, una planta de una fábrica está formada por varias máquinas individuales y estas, a su vez, por varios componentes de diferentes fabricantes. Todos ellos interactúan entre sí y utilizan los servicios de los otros, lo que significa que estos componentes también se facturan mutuamente las prestaciones realizadas. Un componente puede ser una máquina, pero también un pequeño sensor.

Para nuestro prototipo, nos centraremos en un componente que servirá de ejemplo: un motor que ofrece revoluciones como servicio. ¿Pero cómo se puede almacenar de forma segura la facturación de este servicio?

¿Por qué blockchain?

Si cada fabricante almacenara sus datos en su propio sistema y facturara a todos sus clientes en un momento determinado, esto tendría ciertas desventajas. Por ejemplo, nadie podría comprobar si el fabricante está facturando todo realmente de forma correcta y no está engañando a sus clientes. Esto da lugar a un problema fundamental que las tecnologías de registro distribuido (DLT, del inglés «distributed ledger tecnologies») intentan resolver: crear confianza allí donde no existe. Y es que, al tratarse de una cuestión financiera, no suele existir una confianza plena entre el fabricante y el operador.

Las DLT y, por lo tanto, también blockchain, no solo crean esa confianza a través de algoritmos de consenso y procedimientos criptográficos, sino que también ofrecen la ventaja de estar descentralizados. Así pues, no hay un punto único de fallo. En consecuencia, si un fabricante decide que no quiere seguir participando o si un servidor tiene un problema técnico, los datos siguen existiendo distribuidos en todas las demás partes implicadas.

Por lo tanto, las características más importantes que ofrece blockchain para el caso que nos ocupa son las siguientes:

  • Almacenamiento descentralizado de los datos
  • Protección contra falsificaciones
  • Reproducibilidad

También existen otras ventajas y desventajas que no analizaremos en este punto.

Cómo desarrollar una aplicación descentralizada (DApp)

Al principio, es importante saber las tecnologías que van a utilizarse para la aplicación. La elección final depende en gran medida del uso previsto, pues cada tecnología tiene sus propios puntos fuertes y débiles. A continuación, hemos optado por la tecnología EOSIO. 2

Se trata de una tecnología basada en la criptomoneda EOS que la empresa block.one ha desarrollado como proyecto de código abierto. La Initial Coin Offering se prolongó durante todo un año y, con 4100 millones de dólares recaudados, ostenta un récord en este ámbito. El desarrollo del software blockchain, así como las inversiones en las empresas emergentes de EOSIO, se financian a través de este medio.

EOSIO presenta básicamente una estructura muy modular y utiliza el patrón de diseño para plugins, lo que hace que sea relativamente fácil para los desarrolladores personalizar a su gusto el software de los nodos de la red blockchain (que reciben el nombre de «nodeos»). Pero la arquitectura de software de los contratos inteligentes también está muy modularizada en blockchain. En sí, EOSIO cuenta con un algoritmo de consenso de prueba de participación delegada (DPoS, del inglés «delegate proof of stake»). 3 Este se incorpora a su vez a través de los llamados contratos inteligentes del sistema (en inglés, «smart contracts»). Por lo tanto, los propios desarrolladores son los que deciden si desean utilizar dicho algoritmo u otros.

Contrato inteligente

El contrato inteligente para el caso que nos ocupa almacena las solicitudes enviadas al motor con un determinado número de revoluciones. El motor puede procesar estas solicitudes y declararlas como canjeadas. Por lo tanto, una solicitud de servicio tiene el siguiente estado:

Service { buyer, seller, amount, state = (BOUGHT|REDEEMED) }

Y se puede cambiar con las dos transacciones de comprar (en inglés «buy») y canjear (en inglés, «redeem»).

buy(buyer, seller, amount): id

  • Se crea una nueva instancia de la solicitud en blockchain. El comprador («buyer») pide una cantidad («amount») de revoluciones al vendedor («seller»).La transacción devuelve un ID único de la instancia.

redeem(id, seller)

  • Esto canjea una solicitud al vendedor con una identificación (ID).

Los contratos inteligentes en EOSIO se ejecutan en WebAssembly (WASM). Oficialmente, EOSIO solo admite C++. No obstante, como ahora hay muchos compiladores que traducen a WASM, existe una amplia gama de lenguajes de programación posibles. Por ejemplo, nosotros hemos decidido escribir el contrato inteligente en Rust. Además, en GitHub también se puede encontrar un SDK portado a Rust para desarrollar contratos inteligentes EOSIO. 4

Ejecución en Rust

Creamos una nueva biblioteca con cargo.

$ cargo new --lib smartcontract

Para compilar posteriormente la biblioteca a WebAssembly, definimos el tipo de la biblioteca en nuestro Cargo.toml. Asimismo, especificamos allí nuestras dependencias respecto al SDK de EOSIO.

[lib] crate-type = ["cdylib"] [dependencies] eosio = "^0.3.1" eosio_cdt = "^0.3.1" [profile.release] lto = true

En nuestro código de entrada lib.rs importamos primero el SDK de EOSIO, lo que proporciona importantes características y macros que reflejan la API de EOSIO.

use eosio::*; use eosio_cdt::*;

importamos primero el SDK de EOSIO, lo que proporciona importantes características y macros que reflejan la API de EOSIO.

#[derive(NumBytes, Read, Write)] struct Service { id: u64, buyer: AccountName, seller: AccountName, amount: u64, redeemed: bool, }

El struct incorpora las características NumBytes, Read y Write del SDK de EOSIO, para que posteriormente se pueda serializar en blockchain. El tipo AccountName procede del SDK de EOSIO y representa una cuenta en la red blockchain.

La incorporación de la tabla se realiza con la característica Table del SDK, lo que permite serializar el struct Service en forma de tabla en blockchain.

impl Table for Service { const NAME: TableName = TableName::new(n!("service")); type Row = Service; fn primary_key(row: &Self::Row) -> u64 { row.id } }

Con esto, especificamos que las instancias de servicio pueden almacenarse en una tabla en blockchain y la clave primaria se asigna al atributo id.

Una acción para el propio contrato inteligente se define como una función.

#[eosio::action] fn buy(buyer: AccountName, seller: AccountName, amount: u64) { require_auth(&buyer); let smart_contract_account = current_receiver(); let table = Runtime::table(smart_contract_account, n!("global")); let id = table.available_primary_key().expect("There must be an available primary key!"); let runtime = Runtime { id, buyer, seller, amount, redeemed: false }; table.emplace(smart_contract_account, runtime).expect("Could not emplace new bought service."); }

En primer lugar, comprobamos si la cuenta del buyer también corresponde a la cuenta con la que se realizó la transacción, un paso importante que evita además que una máquina ajena cree una solicitud en nombre de otra máquina. A continuación, obtenemos la tabla ya guardada, calculamos el siguiente ID disponible y, una vez más, guardamos en la tabla una nueva instancia de la consulta con los datos transmitidos. La ejecución para la acción de redeem funciona de forma similar.

Definición de la interfaz. ABI

Además del código WebAssembly, el contrato inteligente consta también de una definición que describe la estructura y la interacción con este. Esta se describe en forma de un archivo ABI, como es habitual en el entorno de WebAssembly. Cuando el desarrollo se realiza en C++, este archivo se genera automáticamente. En cambio, en el SDK de Rust, esta función aún no está disponible en la actualidad.

La ABI describe los diferentes tipos y las diferentes acciones del contrato inteligente. También puede escribirse manualmente. Para obtener más información, consulte la documentación para desarrolladores de EOSIO. 5

La interfaz binaria de aplicaciones (ABI) de nuestro contrato inteligente tiene el siguiente aspecto:

{ "version": "eosio::abi/1.0", "types": [], "structs": [ { "name": "buy", "base": "", "fields": [ { "name": "buyer", "type": "name" }, { "name": "seller", "type": "name" }, { "name": "duration", "type": "uint64" } ] }, { "name": "redeem", "base": "", "fields": [ { "name": "id", "type": "uint64" } ] }, { "name": "runtime", "base": "", "fields": [ { "name": "id", "type": "uint64" }, { "name": "buyer", "type": "name" }, { "name": "seller", "type": "name" }, { "name": "duration", "type": "uint64" }, { "name": "redeemed", "type": "bool" } ] } ], "actions": [ { "name": "buy", "type": "buy", "ricardian_contract": "" }, { "name": "redeem", "type": "redeem", "ricardian_contract": "" } ], "tables": [ { "name": "runtime", "type": "runtime", "index_type": "i64", "key_names": ["id", "buyer", "seller"], "key_types": ["uint64", "name", "name"] } ], "ricardian_clauses": [], "abi_extensions": [] }

Para obtener más información sobre la ABI, la generación de contratos inteligentes y la compilación relacionada, visite los siguientes enlaces:

Creación de una red de blockchain EOSIO

El protocolo EOSIO no solo se utiliza en la red EOS. Es posible utilizar una segunda red de prueba oficial para comprobar los contratos inteligentes, o ben crear una red privada propia. La red EOS es de acceso público y, por lo tanto, todos los datos almacenados pueden verse libremente. Sin embargo, en el caso práctico que nos ocupa, no queremos divulgar públicamente los datos confidenciales de facturación y, por lo tanto, establecemos una red aislada de la manera que se indica a continuación.

En EOSIO, básicamente es posible clasificar los nodos en diferentes clases.

  • Existen Light-Nodes, es decir, nodos que solo se conectan a otros nodos, pero que no almacenan ningún dato por sí mismos.
  • Los Full-Nodes almacenan la blockchain en sí, pero no producen ningún bloque por sí mismos.
  • Y luego están Block-Producer, que son los nodos de la red que se han seleccionado para producir los bloques.

Como ejemplo, crearemos dos nodos y configuraremos los dos como productores de bloques. El primer nodo es operado por el fabricante XITASO1 y el segundo, por el fabricante XITASO2. Para simplificar, los dos nodos se ejecutarán en una máquina virtual con Ubuntu 18.04.

En primer lugar, instalamos los archivos binarios necesarios de EOSIO, que están disponibles para los sistemas operativos más habituales. 6

Se instalan tres programas diferentes.

  • keosd – Un demonio que controla una cartera, es decir, el almacén de claves.
  • nodeos – El software real para los nodos de la red blockchain.
  • cleos – La CLI con la que es posible dirigirse a los nodos y acceder a la cartera.

Para empezar, iniciamos nuestro demonio con keosd &y, como tanto los nodos como cleos necesitan acceso a la cartera, creamos una cartera con cleos wallet create --to-console. La cartera debe abrirse primero con cleos wallet open y, luego, desbloquearse con cleos wallet unlock.

Nuestro primer productor de bloques pertenece a la cuenta eosio. Esta es la cuenta predeterminada que existe siempre. eosio firma los bloques con una clave predeterminada. Además, dicha clave también es necesaria para autorizar acciones con la cuenta. La cuenta es siempre igual al principio, solo se utiliza para fines de desarrollo y tiene que sustituirse lo antes posible. Pero primero tenemos que importarla:

$ cleos wallet import 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3

Acto seguido, podemos iniciar el nodo con el siguiente comando.

$ nodeos -e -p eosio \ --data-dir ~/.local/share/eosio/eosio \ --config-dir ~/.local/share/eosio/eosio \ --plugin eosio::producer_plugin \ --plugin eosio::producer_api_plugin \ --plugin eosio::chain_api_plugin \ --plugin eosio::http_plugin \ --plugin eosio::history_plugin \ --plugin eosio::history_api_plugin \ --filter-on="*" \ --access-control-allow-origin='*' \ --contracts-console \ --http-validate-host=false \ --verbose-http-errors \ --disable-replay-opts >> eosio.log 2>&1 &

Además, especificamos que todos los datos se almacenen en la carpeta .local/share/eosio/eosio. Los parámetros --data-dir y --config-dir son opcionales, pero deben especificarse para una red de múltiples nodos, puesto que, de lo contrario, todos los nodos utilizarán la misma ubicación. Además, iniciamos el nodo con unos cuantos plugins que son necesarios para la producción de bloques o para la comunicación entre cleos y nodeos. Para obtener más información sobre el manejo nodeos visite el siguiente enlace:

El sistema de cuentas en EOSIO tiene una estructura de árbol. Cada cuenta solo puede crearse a partir de otra cuenta y queda subordinada a esta. De este modo, para nuestro segundo bloque de productores, necesitamos una segunda cuenta. Para ello, primero creamos una nueva pareja de claves compuesta por una clave pública y otra privada.

$ cleos wallet create_key

Este comando devuelve la parte pública de la clave en la consola. Lo asignaremos a nuestra segunda cuenta inita.

$ cleos create account eosio inita <PublicKey>

Como ya hemos mencionado, el sistema de contratos inteligentes tiene una estructura muy modular. Así, la función para establecer los productores de bloques activos se incorpora en un contrato inteligente de sistema bajo. Para instalarlo, necesitamos descargarlo y compilarlo.

$ git clone https://github.com/EOSIO/eosio.contracts --branch v1.7.0 --single-branch $ wget https://github.com/EOSIO/eosio.cdt/releases/download/v1.6.3/eosio.cdt_1.6.3-1-ubuntu-18.04_amd64.deb $ sudo apt install ./eosio.cdt_1.6.3-1_amd64.deb

Estos comandos clonan el proyecto de código abierto de los contratos inteligentes del sistema de EOSIO e instalan el SDK de desarrollo de contratos inteligentes en C++.

Para la compilación, además del build-essential, también se necesita cmake.

$ sudo apt install build-essential cmake -y

Una vez que la instalación ha finalizado correctamente, compilamos los proyectos para contratos inteligentes.

$ cd /eosio.contracts/ $ rm -fr build $ mkdir build $ cd build $ cmake .. $ make -j$( nproc ) $ cd ..

La instalación de contratos inteligentes del sistema debe habilitarse con el siguiente comando. En la versión 2.0, esto se hace con la siguiente llamada a la API.

curl -X POST http://127.0.0.1:8888/v1/producer/schedule_protocol_feature_activations -d '{"protocol_features_to_activate": ["

A continuación, podemos instalar el contrato inteligente responsable eosio.bios.

$ cleos set contract eosio /build/contracts/eosio.bios

Ahora especificamos nuestros productores de bloques en un archivo schedule.json. No obstante, para, ello seguimos necesitando dos nuevas parejas de claves que servirán como claves de firma para los bloques.

$ cleos wallet create_key # output = <PublicKeyEOSIO> $ cleos wallet create_key # output = <PublicKeyINITA>

Después, describimos nuestro productor de bloques activo.

{ "schedule": [ { "producer_name": "eosio", "block_signing_key": "<PublicKeyEOSIO>" },{ "producer_name": "inita", "block_signing_key": "<PublicKeyINITA>" } ] }

A continuación, enviamos esta programación a blockchain utilizando el contrato inteligente instalado.

$ cleos push action eosio setprods "<path-to-json>/schedule.json" -p eosio@active

Con ello, hemos determinado dos productores de bloques activos, cada uno de los cuales firma los bloques con claves diferentes. A continuación, iniciamos nuestro segundo nodo inita para que este pueda copiar el historial de blockchain anterior de
eosio. Para ello, también necesitamos la parte privada de la pareja de claves que acabamos de crear. A tal fin, mostramos las claves almacenadas en la cartera.

$ cleos wallet private_keys
$ nodeos -e -p inita \ --data-dir ~/.local/share/eosio/inita \ --config-dir ~/.local/share/eosio/inita \ --http-server-address 0.0.0.0:8889 \ --p2p-listen-endpoint 0.0.0.0:9877 \ --p2p-peer-address 127.0.0.1:9876 \ --plugin eosio::producer_plugin \ --plugin eosio::net_api_plugin \ --plugin eosio::chain_api_plugin \ --signature-provider <PublicKeyINITA>=KEY:<PrivateKeyINITA> \ >> inita.log 2>&1 &

Al hacerlo, iniciamos este segundo nodo solo con los plugins que necesitamos y definimos otros puertos para nuestros propios puntos finales, pues los predeterminados ya están ocupados por el primer nodo.

Sin embargo, el nodo eosio aún no tiene su clave asignada, por lo que debemos reiniciarlo.

$ ps $ kill $ nodeos -e -p eosio \ --data-dir ~/.local/share/eosio/eosio \ --config-dir ~/.local/share/eosio/eosio \ --plugin eosio::producer_plugin \ --plugin eosio::producer_api_plugin \ --plugin eosio::chain_api_plugin \ --plugin eosio::http_plugin \ --plugin eosio::history_plugin \ --plugin eosio::history_api_plugin \ --filter-on="*" \ --access-control-allow-origin='*' \ --contracts-console \ --http-validate-host=false \ --verbose-http-errors \ --disable-replay-opts \ --signature-provider <PublicKeyEOSIO>=KEY:<PrivateKeyEOSIO> \ >> eosio.log 2>&1 &

Ahora tenemos una red de múltiples nodos en funcionamiento en la que podemos instalar nuestro contrato inteligente construido por nosotros mismos. También queremos asignarlo a una cuenta separada. Además, necesitamos al menos dos cuentas de prueba para probar nuestro caso práctico.

Para ello, volvemos a crear tres nuevas parejas de claves. Una para cada cuenta.

$ cleos wallet create_key # 3x

A continuación, crearemos las nuevas cuentas e instalaremos el contrato inteligente en la cuenta iot.

$ cleos create account eosio iot <PublicKeyIOT> $ cleos create account iot testbuyer <PublicKeyBuyer> $ cleos create account iot testseller <PublicKeySeller>

Después, instalamos nuestro contrato inteligente. Por supuesto, este ya debe haberse compilado en WebAssembly.

$ cleos set abi iot <path-to-smart-contract>/smartcontract.abi $ cleos set code iot <path-to-smart-contracts-wasm>/smartcontract.wasm

Con esto, hemos enviado una transacción con el contrato semántico y el código asociado a la red blockchain y la hemos almacenado en esa ubicación.

Sobre las claves de las cuentas

EOSIO subdivide las parejas de claves de las cuentas. Hemos asignado una clave de propietario a todas las cuentas. Sin embargo, para ello, se puede y se debe seguir subdividiendo una clave Active. Todas las interacciones y transacciones deben realizarse con esta clave, puesto que, si la roban o se pierde, puede sustituirse por medio de la clave del propietario. La clave del propietario no se puede cambiar sin más.

La conexión con la red

Para probar nuestra aplicación (DApp), necesitamos un cliente que interactúe con el sistema creado. Para ello, EOSIO proporciona un cliente nodo oficial eos.js, que puede instalarse con npm.

Antes de poder enviar una transacción a la red con este cliente, necesitamos la clave privada de una cuenta, que luego firmará dicha clave. Para reclamar un servicio, utilizamos la cuenta testbuyer. Para encontrar las claves de la cuenta, podemos utilizar cleos para consultar la red y, luego, nuestra cartera.

$ cleos get account testbuyer # -> Owner Pulic Key $ cleos wallet private_keys # Eintrag mit Public Key finden

Para conectarse a la red a través de eos.js , el cliente proporciona dos clases. JsonRpc establece la conexión rpc con el nodo y la Api, a su vez, utiliza JsonRPC y se encarga de la codificación y del resto de la lógica. Además, tenemos que transmitir la clave privada en una instancia SignatureProvider de la Api . Para el prototipo, utilizamos el JsSignatureProvider que, sin embargo, solo está pensado para fines de desarrollo.

import { JsSignatureProvider } from 'eosjs/dist/eosjs-jssig'; import { JsonRpc, Api, RpcError } from 'eosjs'; import fetch = require('node-fetch'); import { TextEncoder, TextDecoder } from 'util'; const hostUrl = 'http://127.0.0.1:8888'; const privateKey = ''; const signatureProvider = new JsSignatureProvider([privateKey]); const rpc = new JsonRpc(hostUrl, { fetch } ); const api = new Api({rpc, signatureProvider, textDecoder: new TextDecoder(), textEncoder: new TextEncoder()}); function buyService(amount) { const payload = { account: 'iot', name: 'buy', authorization: [{ actor: 'testbuyer', permission: 'active' }], data: { buyer: 'testbuyer', seller: 'testseller', duration: amount, } }; const options = { blocksBehind: 3, expireSeconds: 30 }; try { return await api.transact({actions: [payload]}, options); } catch(err) { console.log("Could not transact: " + err); if (err instanceof RpcError) console.log(JSON.stringify(err.json, null, 2)); } }

Así es como podría ser la función para una solicitud de compra de un servicio en el lado del cliente. eos.js ofrece además la posibilidad de consultar los datos y la información almacenados mediante bloques. Estas funciones se incorporan en los nodeoscon la ayuda de los plugins de nodeos.

Resumen

Por un lado, hemos visto la forma en la que se configura una red de múltiples nodos con EOSIO, así como el modo en el que se instalan varios contratos inteligentes en ella y la manera en la que las cuentas necesarias se configuran con permisos. También hemos analizado brevemente la integración del cliente con eos.js. Con el prototipo que hemos desarrollado, hemos esbozado las posibilidades que presenta EOSIO. Gracias a sus excelentes funciones de documentación, EOSIO ofrece un acceso fluido al desarrollo con la tecnología blockchain.

En nuestro caso práctico, hemos demostrado cómo podría ser una plataforma digital interoperable en un entorno industrial para incorporar nuevos modelos de negocio, como el pago por uso. Las nuevas tecnologías blockchain, como EOSIO, permiten aplicar de forma rápida y sencilla una gestión segura de los procesos y, por lo tanto, ofrecen un enorme potencial para la industria.

Autores y personas de contacto

¿Tiene preguntas, ideas o comentarios sobre este tema? Póngase en contacto con nosotros.

2019 04 03 Michael Damboeck

Michael Damböck
michael.damboeck@xitaso.com

Jonas Geschke

Jonas Geschke
jonas.geschke@xitaso.com