En Mi Local Funciona

Technical thoughts, stories and ideas

Más que criptomonedas. Esenciales Blockchain & Ethereum. Parte II

Publicado por Ángel Martínez el

BlockchainNodosRedesConsensoGethAPI JSON-RPCWeb3DApp

Siguiendo con esta serie, en el presente artículo vamos a ser ambiciosos y analizaremos y clasificaremos los tipos de redes y de nodos (o clientes) existentes. Posteriormente nos adentraremos en los modelos y algoritmos de consenso más conocidos.

Después, tal como ya indiqué en la primera entrega, vamos a seguir estudiando nuestro cliente Geth; concretamente su avanzada CLI. En este punto aparecerá la JSON-RPC API (aunque ya la hemos vislumbrado anteriormente) y la presentaremos formalmente.

Para finalizar, haremos una introducción a las famosas DApps y cómo interactúan con el backend, es decir, con la red blockchain, esto es, mediante la Web3 API.

Empecemos

Las redes como Bitcoin, Ethereum, Litecoin o Monero se denominan Públicas, ya que cualquiera puede unirse y participar; están abiertas y contienen algún mecanismo de incentivo para animar a más participantes a unirse a la misma.

Por otro lado, redes como Hyperledger o R3 (Corda), son redes Privadas (financiadas muchas por consorcios de empresas) en las que tanto el proceso de participación y/o el proceso de consenso están limitados.

Existen dos conceptos que pueden combinarse con los dos tipos de redes anteriores y que en muchos foros los utilizan como sinónimos, pero que realmente no lo son. Me refiero a las Redes no permisionadas (permissionless networks), y las Redes permisionadas (permissioned networks), respectivamente.

En las redes no permisionadas, las transacciones pueden ser vistas por cualquier participante, y cualquiera puede lanzar también transacciones (y desplegar contratos). En las redes permisionadas, los participantes pueden ver solamente las transacciones relevantes para ellos o podrían ver todas las transacciones, así como lanzar a la red o no, nuevas transacciones (desplegar contratos).

Aunque podríamos pensar que una red pública es no permisionada, y una privada es permisionada, vemos que hay una diferencia semántica: en una red privada, necesito aprobación para participar en ella, y aun así solamente podría tener permisos para realizar ciertas operaciones/transacciones.

Otro asunto a destacar es que en las redes Blockchain, cada nodo u ordenador que se conecta juega un rol particular, y según la implementación de dicha red y según el algoritmo de consenso utilizado, tienen determinados nombres. Por ejemplo, nodo regular o de trabajo, nodo validador, nodo bootstrap (o de arranque), nodo minero, nodo sealer (o sellador) ...

En las redes Bitcoin principalmente existen los nodos completos (full nodes) que poseen toda la cadena de bloques (unos 160GB a día de hoy, según https://blockchain.info/charts/blocks-size?timespan=all), y verifican las transacciones que contienen para asegurarse de que estén completamente validados. Este tipo de nodos, con estas comprobaciones y validaciones, podrá confiar en la integridad de la red sin confiar expresamente en el minero.

También este tipo de nodos ofrecen otros tipos de servicios como transmitir y difundir bloques a otros nodos, presentar datos históricos, y ayudar a los nodos ligeros (lightweight nodes) que no tienen toda la cadena descargada (solamente las cabeceras de los bloques), a encontrar y procesar sus propias transacciones.

Consenso y Algoritmos

Llegado a este punto, vamos a profundizar en otra área importante que son los algoritmos de consenso. Con ello, tendremos un conocimiento bastante completo de toda esta tecnología.

Recordemos que el Consenso se refiere al proceso por el cual aseguramos la red Blockchain y por el cual validamos y ordenamos (evitando el doble gasto) las transacciones creadas por los participantes.

En las redes públicas cualquier nodo puede tener este rol de verificación, actualización e incorporación de bloques: basta con que reúna los requisitos y recursos necesarios. En cambio, en las redes privadas, este rol dependerá de los participantes, de la configuración propuesta y de los reglamentos definidos en dicha red: no se requiere un consenso mayoritario como en las redes públicas.

Hay múltiples modelos de consenso, pero hay dos típicos y archiconocidos que son Proof of Work y Proof of Stake.

Se basa en algoritmos Hash, siendo en Bitcoin calificado como Hashcash y en Ethereum apodado como Ethash (análogo al anterior, pero evita el uso de procesadores ASIC debido al uso intensivo de movimientos de datos en memoria). Coloquialmente, es conocido por el nombre de ‘minería’ y los nodos que se dedican a ello como ‘mineros’. Es un algoritmo costoso de resolver, pero muy fácil de verificar.
Funcionalmente es como sigue:

PoW

Como vemos, el uso de estas funciones matemáticas consume en el software de minado mucha energía y es razonable pensar que los ‘mineros’ se concentren en regiones geográficas con bajo coste eléctrico. Así mismo, podemos observar que el nodo con mayor capacidad de cómputo será el que acredite la transacción y cobre la recompensa (incentivo) asociada por este uso y gasto en sus recursos.

Este proceso no se basa en cómputo si no en el mayor porcentaje de posesión de tokens emitidos: digamos que depende de la riqueza (cantidad de monedas que tiene uno acumulado en un monedero conectado a la red) o de su participación (incluso buen comportamiento) en la red. Los nodos se conocen como ‘validadores’ y por ejemplo si el nodo X posee 2 monedas y el nodo Y tiene 1 moneda, entonces X tiene el doble de probabilidad de que sea llamado para validar un bloque de transacciones. Aquí se usan procesadores genéricos que consumen menor energía que en PoW.

Hay dos variantes notables:

Prueba de Importancia, Proof of Importance o PoI, que intenta evitar únicamente la acumulación de tokens y añade una ponderación a los participantes según su verdadera contribución en el sistema.

Prueba de Participación Delegada, Delegated Proof of Stake o DPoS, en la que ciertos ‘validadores’ pueden delegar sus derechos de participación en el consenso, votando a un determinado ‘validador’ o ‘representante’.

Esos dos algoritmos (PoW y PoS) se centran en redes públicas; en redes privadas y permisionadas se suele utilizar otros más eficientes: al fin y al cabo, aquí los participantes tienen la capacidad de restringir o asignar quién puede participar en el mecanismo de consenso, por lo que la potencia de cómputo y la acumulación de moneda no entran en juego o no son criterios para considerar. Revisemos los más llamativos.

Básicamente, mediante el envío de mensajes entre los nodos ‘validadores’ se intenta averiguar si existe alguno que falla o perturba a la red para aislarlo del sistema.

Existen versiones de implementación como son:

Practical Byzantine Fault Tolerance o PBFT

Federated Byzantine Agreement o FBA

Istambul Byzantine Fault Tolerance o IBFT

  • Proof of Authority o PoA

Es un protocolo donde las transacciones son validadas por cuentas pre-aprobadas, algo así como los ‘administradores’ del sistema. Lógicamente, esta naturaleza centralizada hará que sea una implementación muy poco probable en una red pública.

Al nodo ‘validador’, en este contexto, se denomina ‘sealer’ o sellador.

Ethereum puede ser configurado para usar PoA, a través del protocolo Clique (ver más abajo, en TestNets).

Así que implementar una red privada o un consorcio basado en Ethereum y PoA es una solución muy válida: segura en cuanto a si confías en los nodos ‘sealers’, rápida en generación de bloques y computacionalmente poco intensiva.

Desarrollado por Intel, este consenso es un híbrido entre una lotería y un orden de llegada: cada nodo ‘validador’ recibe un tiempo de espera aleatorio y el ‘validador’ que tenga el menor tiempo de espera para un bloque de transacciones en particular, será elegido líder y creará el siguiente bloque.

Tras estos mecanismos y tipos de redes, vamos ahora a centrarnos en Ethereum que posee varias redes para pruebas. Son las llamadas redes de test o TestNets. En su red de producción o MainNet, actualmente se usa PoW (bajo el protocolo Ghost) y se desea migrar a PoS (nuevo protocolo Casper) con la ventaja principal de reducir el consumo energético.

Redes principales de Test:

Ropsten

-Basada en PoW

-La más análoga al actual entorno de producción

-Usada por los clientes Geth y Parity(*)

-Chain ID: 3

-Generación de bloques entre 20 a 30 sg.

Kovan

-Basada en PoA

-Nos es soportada por Geth, solamente por Parity(*)

-Chain ID: 42

-Generación de bloques alrededor de 5 a 10 sg.

-ETH no puede ser minado, debe ser solicitado desde un faucet(**)

Rinkeby

-Basada en PoA

-Solamente soportada por Geth

-Chain ID: 4

-Generación de bloques alrededor de 15 sg, pero es configurable

-ETH no puede ser minado, debe ser solicitado desde un faucet(**)

Morden

-Está descatalogada

-Chain ID: 2

La Ethereum pública MainNet tiene como identificador Chain ID el número 1.

(*) Parity es un cliente Ethereum implementado en Rust que posee además una Interfaz Gráfica. El objetivo es ser más ligero, rápido y seguro que Geth.

(**) Un faucet o grifo es generalmente una web que te proporciona criptomoneda a cambio de realizar algún comentario en una red social promocionando la misma.

La CLI de Geth

Geth es el cliente Ethereum escrito en Go o golang, necesario para participar o interactuar con la red.

Posee una Línea de Comandos con muchas posibilidades. Vamos a realizar un pequeño estudio de todo este potencial.

La sintaxis general es:
> geth [options] command [command options] [arguments...]

Las [options] se clasifican en varios grupos:

  1. Configuración.
  2. APIs.
  3. Consola.
  4. Cuentas.
  5. Gas.
  6. Minería.
  7. Logging.
  8. Depuración.
  9. Rendimiento y EMV.
  10. Networking.
  11. Opciones en desarrollo o experimentales.
  12. Miscelánea.

Los command en:

  1. Gestión de ficheros y Base de Datos.
  2. Inicialización ('init').
  3. Cuentas
  4. Consola interactiva (*).

(*) La consola interactiva es otro interfaz que proporciona Geth, y que veremos en el siguiente apartado. Es una API Javascript para interactuar también con la red y en el fondo es un envoltorio de la API de comunicación JSON-RPC.

Antes de todo, un pequeño gráfico sobre cómo trabajamos con el cliente Geth a nivel de comunicaciones, redes y APIs.

Comunicaciones

Opciones de Configuración

--datadir "/chain-data" El directorio para escribir los datos de la cadena.

--keystore "/key-data" El directorio para el almacén de claves (por defecto dentro del directorio anterior datadir).

--networkid "value" El ChainID que vimos anteriormente (por defecto, 1 MainNet).

--testnet Se conecta al nodo de la TestNet Ropsnet.

--rinkeby Se conecta al nodo de la TestNet Rinkeby.

--syncmode "fast" Modo de sincronización(*)

--identity "MyNode" Nombre del nodo personalizado

--dev Modo desarrollador (red privada de un único nodo con una cuenta predefinida y saldo; con múltiples opciones de depuración y logging). En contraposición con --testnet.

(*) Modo de sincronización:

‘full’ tengo el estado completo de la cadena: cabeceras y cuerpos de los bloques y todo el historial de las transacciones.

‘fast’ tengo todos los bloques (cabeceras y cuerpos), pero solamente almacena los estados recientes de las transacciones (las últimas 1024).

‘light’ tiene solamente las cabeceras de los bloques. Parecido a un snapshot de la red. Es el más rápido en sincronizar, pero el menos seguro.

Opciones de APIs

JSON-RPC

--rpc Habilita JSON-RPC.

--rpcaddr "host" Por defecto localhost.

--rpcport "port" Por defecto 8545.

--rpcapi "value, ..., " APIs ofrecidas sobre el interfaz JSON-RPC (por defecto eth, web3 y net).

--rpccorsdomain "dominios, ..., " o "*" Lista separada de dominios para evitar problemas con CORS (se añaden las cabeceras oportunas).

WS-RPC

--ws Habilita WS-RPC.

--wsaddr "host" Por defecto localhost.

--wsport "port" Por defecto 8546.

--wsapi "value, ..., " APIs ofrecidas sobre el interfaz WS-RPC.

--wsorigins "origen" Origen para aceptar WS solicitudes.

IPC-RPC

--ipcdisable Deshabilita IPC-RPC (por defecto está habilitado).

--ipcpath "geth.ipc" Ruta y nombre del fichero para el socket/pipe IPC.

Opciones de Consola

--jspath "loadScript" Path de los scripts JS, por defecto "."

--exec "JS statement" Ejecuta una sentencia de la API Javascript (usado con los comandos 'console' y 'attach').

--preload "files, ..., " Ficheros JS para precarga, usado con el comando 'console'

Ejemplo 1.
> geth --verbosity "0" --datadir "./chain-data" --testnet --exec "personal.listAccounts" console ["0x... "]

Ejemplo 2. Supongamos que utilidades.js contiene funciones JS, entonces dentro de la 'console' puedes llamarlas.
> geth --verbosity "0" --datadir "./chain-data" --testnet --preload "./scripts/utilidades.js" console

hacerAlgo()

Opciones de Cuentas

--unlock "lista de cuentas separadas por coma o índices del array de cuentas" Las cuentas están por defecto bloqueadas.

--password "password file" Fichero de contraseñas (para una entrada no interactiva).

Opciones de Minería

--mine Habilita el minado.

--minerthreads "hilos" Número de hilos para minar.

--etherbase "cuenta" Dirección pública para cargar las recompensas del minado (por defecto la primera de la lista o índice "0").

--targetgaslimit "value" Máximo Gas gastado por bloque.

--gasprice "value" Precio del gas mínimo para aceptar minar una transacción.

--extradata "datos" Añade datos extra al bloque (no a la transacción). Hecho por el minero.

Opciones de Gas

--gpoblocks "value" Número de bloques recientes para verificar el precio de Gas (por defecto 10).

--gpopercentile "value" El precio del gas sugerido es el percentil dado de un conjunto de precios de gas de transacciones recientes (por defecto, 50).

Opciones de Logging

--verbosity "value" 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail (por defecto: 3).

--fakepow Deshabilita la verificación de PoW.

--trace "filename" Volcado de las trazas a un fichero.

Opciones de Redes

--bootnodes "value" Los pares pueden ser añadidos manualmente o mediante bootnodes (nodos de arranque). Aquí se enumeran los enodes (separados por coma) que funcionan como nodos de arranque y realizan el descubrimiento de pares.

--port "value" Puerto de comunicación entre nodos de la red (por defecto 30303).

--maxpeers "value" Número máximo de pares (nodos) de la red (por defecto 25, si es 0 se deshabilita la red).

--nodiscover Deshabilita el mecanismo de descubrimiento de pares para este nodo.

--netrestrict "value" Restringe los intentos de conexión entrantes a las IPs o máscaras CIDR indicadas.

Comandos de Cuentas

account new Crea una cuenta.

account list Lista todas las cuentas.

account update Actualiza la contraseña de la cuenta.

account import Importa el fichero de claves.

Ejemplo 1.
> geth --datadir "./chain-data" --testnet account list

Account #0: xxxxxxx

Account #1: yyyyyy

Ejemplo 2.
> geth --datadir "./chain-data" --testnet account new

Your new account...

Passphrase:

...

Address: ...

Comandos de Consola interactiva

console Inicia una sesión interactiva de consola.

attach "dirección del pipe" o "http://...:8545" o "ws://...:8546" Se conecta a un cliente ya corriendo.

Consola JavaScript de Geth

Como acabamos de ver, Geth sirve APIs usando HTTP, WebSocket y otros protocolos para que las aplicaciones externas se comuniquen con él, y por extensión se comuniquen con la red Blockchain.

Geth implementa en su consola interactiva un entorno de ejecución (runtime) JavaScript, con el cual podemos ejecutar código JavaScript y por otro lado podemos invocar a la API de Gestión o Management API que proporciona diversos componentes para usarlos: admin, personal, miner, txpool, debug y web3.

Tres enlaces con información imprescindible son:

Consola JavaScript de Geth

API de Gestión

API JSON-RPC

A continuación, revisaremos las opciones más llamativas de esta API JavaScript.

  • admin

    Gestión de nodos y pares

    admin.nodeInfo

    admin.datadir

    admin.peers

    admin.peers.length

    admin.peers[0]

    admin.addPeers(url en formato enode://)

    Añade el peer pero no persiste su información: mejor usar un fichero de nodos estáticos ‘static-nodes.json’.

    Gestión de la cadena de bloques

    admin.exportChain(filename)

    admin.imporChain(filename)

    Desde un nodo sincronizado podemos exportar la cadena de bloques para importarla en un nuevo nodo. Es un método mucho más rápido para preparar un nuevo nodo.

    Gestión de interfaces RPC

    admin.startRPC(...)

    admin.startRPC("localhost", 8545, "web3")

    admin.stopRPC()

    admin.startWS(...)

    admin.stopWS()

  • personal

    Gestión de cuentas

    personal.listAccounts

    personal.newAccount("password")

    personal.lockAccount(...)

    personal.unlockAccount(...)

    personal.sendTransaction(txn, "password")

    txn = {from: "addressFrom", to: "addressTo", value: "valueInWei"}

  • miner

    Gestión de minería

    miner.start(numero_hilos)

    miner.stop()

  • txpool

    Contadores, resumen y detalle de las transacciones en el pool

    txpool.status

    txpool.inspect

    txpool.content

    Las transacciones pendientes son transacciones válidas y que están preparadas para ser procesadas e incluidas en el bloque (a la espera de ser minadas).

    Las transacciones encoladas son transacciones cuyo ‘nonce’ no está en secuencia y pasarán a pendiente cuando su orden sea correcto. El ‘nonce’ es un contador incremental y único de transacción por cuenta o dirección origen.

  • debug

    Información de depuración

    debug.verbosity(nivel de log)

    debug.dumpBlock(numero)

    debug.traceBlockByNumber(numero)

    debug.traceBlockByHash(hash)

    debug.traceTransaction(txn)

    Rendimiento

    debug.gcStats()

    debug.memStats()

    debug.cpuProfile(fichero, segundos)

    debug.startCPUProfile(fichero)

    debug.stopCPUProfile()

    Depuración a nivel de lenguaje Go

    debug.goTrace(fichero, segundos)

    debug.stacks()

    debug.vmodule(identificador)

  • web3

    Es la API Web3 que sustenta el desarrollo de DApps y que veremos en el siguiente módulo.

    web3.eth.accounts

    eth.accounts

    web3.net.listening

    net.listening

    web3.fromWei(eth.getBalance(eth.coinbase), "ether")

    Se puede abreviar si usamos los objetos que contiene eth, net, db y shh.

Introducción a las DApps

Una DApp o Aplicación descentralizada (Decentralized Application), es una aplicación web cuyo backend corre sobre una red P2P (peer-to-peer o red de pares) descentralizada y su código fuente es open source. En contraste a las aplicaciones web estándar, que tienen los recursos centralizados y son propiedad de organizaciones y empresas.

Cuando trabajamos con DApps, los programadores necesitarán acceder a la información de la cadena de bloques, así como a las transacciones. Para ello, está la API JSON-RPC que proporciona la red (cliente Geth), pero existe un wrapper o librería JavaScript que conecta tu navegador a la Blockchain y por tanto te ayuda a crear y trabajar con DApps. Se llama API Web3 y la librería web3.js.

Esta librería Web3 nos proporciona un subconjunto de funcionalidades respecto a las ofrecidas por la Consola interactiva JavaScript de Geth, vista en la sección anterior.

La API Web3 es como si fuera otro servidor corriendo en otro puerto y mientras que el navegador se conecta al servidor web por el puerto 80/443, lee todos los recursos (imágenes, CSS, ...) y parsea JavaScript, Web3 se conecta por el puerto 8545 (por defecto) a la JSON-RPC.

Web3 proporciona los siguientes objetos:

  • eth Para interactuar con la Blockchain Ethereum.
  • net Para interactuar con el estado de la red y el nodo.
  • db Para interactuar con la base de datos local LevelDB.
  • shh Para interactuar con la mensajería P2P usando el protocolo estándar Whisper.

Ejemplo.
var Web3 = require('web3');

var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545));

var balance = web3.eth.getBalance(web3.eth.coinbase);

Una prueba de DApp es el plugin de Chrome llamado MetaMask que enlaza la red Ethereum con el navegador sin necesidad de tener un nodo o cliente local corriendo.

MetaMask

Para finalizar, una reflexión: Geth (y la red Ethereum) proporciona una API JSON-RPC para interactuar. Pero, para no estar lidiando con los mensajes JSON, los verbos HTTP y las cabeceras, nos equipa con una API JavaScript y un modelo de objetos completo, que podemos usar desde la Consola interactiva de Geth o desde nuestras aplicaciones externas mediante la librería web3.js.

Muchas funcionalidades son comunes entre la CLI de Geth y la API JavaScript (tanto desde la Consola, como la API Web3).

Espero que os haya resultado interesante este post y os animo a profundizar con los conceptos y herramientas aquí mostradas.

Si te ha gustado te invito a que nos veamos en el próximo evento Blockchain Spain, donde habrá interesantes charlas sobre casos de uso y detalles técnicos. Y por supuesto, puedes estar al día de próximos posts siguiendo a nuestra cuenta de Twitter.

¡Hasta la próxima! TAGITSMART MINETAD