Índice
- Introducción
- Generando un Hash SHA256
- Transacciones
- Sellando bloques
- Proceso de minado
- Red
- Mecanismos de poda
- Conclusión
Introducción
En el anterior tutorial os enseñaba algo muy sencillo, cómo comprar criptomonedas, sin tener prácticamente ni idea de lo que es, y cómo invertir gracias a las facilidades de Binance. Aunque ojito, si delegas la gestión/custodia de tus criptomonedas a una tercera empresa, si la hackean, te puedes quedar sin ellas. Todo esto entraña su riesgo que debéis valorar!!!
Puedes ver el resto de tutoriales de la serie de criptomonedas aquí:
Cómo comprar e invertir criptomonedas en Binance: https://adictosaltrabajo.com/2022/01/14/como-comprar-e-invertir-criptomonedas-en-binance/
Votación con contratos inteligentes en Remix: https://adictosaltrabajo.com/2022/01/31/votacion-con-contratos-inteligentes-en-remix/
Usando la wallet MetaMask y la red local Ganache: https://adictosaltrabajo.com/2022/02/09/usando-la-wallet-metamask-y-la-red-local-ganache/
Compilación y despliegue de contratos inteligentes con Truffle y Ganache: https://adictosaltrabajo.com/2022/02/16/compilacion-y-despliegue-de-contratos-inteligentes-con-truffle-y-ganache/
Creando tokens Ethereum: https://adictosaltrabajo.com/2022/03/14/creando-tokens-ethereum/
Ahora voy a compartir mi investigación sobre las criptomonedas acudiendo a los conceptos básicos.
Podríamos decir que la carrera de las criptomonedas modernas empezó cuando Satoshi Nakamoto (pseudónimo, por lo que no se sabe quién es de verdad) publicó un paper (documento técnico) sobre Bitcoin: un sistema de dinero en efectivo peer-to-peer.
Podéis encontrar este paper aquí https://bitcoin.org/files/bitcoin-paper/bitcoin_es.pdf y voy a capturar algunas porciones. Es tan corto que merece la pena leerlo.
Dentro del sistema de criptomonedas, realmente lo que se maneja es una base de datos invariable a modo de libro contable, donde cada propietario transfiere la moneda al siguiente propietario firmando digitalmente con el hash de la transacción previa y la clave pública del siguiente propietario.
Vamos a ir viendo cada uno de estos conceptos.
Generando un Hash SHA256
Chelu Martín (@ChezluiCJar) me ha propuesto este enlace en el que podéis experimentar con estos conceptos (sin instalar nada): https://andersbrownworth.com/blockchain/hash
Podéis ver cómo se genera un Hash SHA256 a partir de un conjunto de datos.
Si queréis jugar programando también lo podéis hacer con Libros Jupyter gracias a Colab en https://colab.research.google.com
Este es un ejemplo básico en Python. En este caso he simplificado el coste de generar un hash usando Hash md5 pero para el caso es el mismo: entender los conceptos.
import hashlib hash_hmd5 = hashlib.md5() sTextoBase="Con cien cañones por banda" hash_hmd5.update(sTextoBase.encode()) sRepresentacionHash = hash_hmd5.hexdigest() print ("El hash de " + sTextoBase + " es " + sRepresentacionHash)
El hash de Con cien cañones por banda es fa005b4d2d544d52aa159ebac47fc9b0
Transacciones
Las transacciones (firmadas) se agrupan en bloques.
En los sistema de encriptación por clave asimétrica cualquier persona puede crear un conjunto de claves (privada/publica), asociadas matemáticamente, de tal modo que lo que se ha codificado con la clave privada solo se puede decodificar con la clave pública correspondiente y al revés, para contestar con seguridad.
De ese modo, las claves privada/pública se generan por el usuario y la privada no se comparte con absolutamente nadie. La clave pública se comparte con los todos demás. Si alguien quiere mandarte un mensaje, aunque no sepa quién eres, puede codificarlo con tu clave pública y, por mucho que se intercepte, no se podrá decodificar si no es con la clave privada (por lo menos en un tiempo razonable de computación).
Si se manda un mensaje y alguien es capaz de decodificarlo en mil años se puede considerar seguro. Pasaría lo mismo si son necesarios meses para decodificar un mensaje que tiene una importancia de segundos. Por tanto, la complejidad de la codificación (por tanto el coste energético) tiene que estar siempre ligada a estas variables. Por ejemplo, se podría negociar con claves asimétricas entre dos servidores una clave de comunicación simétrica (la misma clave para enviar y transmitir información) que es mucho menos costosa computacionalmente. Si esa clave simétrica se utiliza por unos minutos, y la información no tiene valor pasado ese tiempo, puede ser un sistema ligero a nivel energético y seguro en ese contexto. Esto se usa en las comunicaciones cliente-servidor seguras Web.
Cuando sea una realidad la computación cuántica, y sea mucho más fácil resolver los problemas actuales, la complejidad y longitud (en bytes) de estas claves es posible que se tengan que ampliar.
Sellando bloques
Ahora el problema es garantizar la seguridad del dinero en un sistema distribuido de transacciones donde no hay una autoridad central ¿cómo evitamos que se pague dos veces con la misma moneda? Para ello se tienen que enviar todos los mensajes con las transacciones a toda la red con algún sistema que evite el doble pago y que no se pueda modificar el histórico de transacciones realizadas, ya que desconocemos la identidad real de los propietarios (solo sus claves públicas).
Para garantizar la invariabilidad en el tiempo se pueden sellar los bloques, esto significa generar un hash y añadirlo al siguiente bloque. Si ese hash se incorpora en el siguiente bloque, como parte del mensaje, y se genera un nuevo hash es imposible que alguien cambie los datos pasados sin afectar las comprobaciones de los hash de los siguientes bloques.
A medida que se generan los bloques, y se envían a toda la red, los servidores empiezan a componer nuevos bloques en base a los bloques existentes, de este modo, se van produciendo cadenas de bloques cada vez más largas. Como esto pasa concurrentemente en distintos servidores con posibles problemas de conectividad, rendimiento, etc. se darán cadenas más cortas y más largas en distintas partes del sistema. Solo se darán por válidas las cadenas más largas por lo que los servidores que estén trabajando en las más cortas tendrán que adaptarse y volver a reflejar las transacciones que no han quedado consolidadas en un bloque en el sistema.
Aquí se introduce otro concepto interesante que son los algoritmos de consenso que hacen posible que haya mayorías a la hora de determinar, en el sistema distribuido, cuál es la cadena válida. Os recomiendo este enlace: https://101blockchains.com/es/algoritmos-de-consenso-blockchain/
Por tanto, los servidores pueden tener que mantener dos cadenas simultáneamente hasta comprobar cuál es la dominante en el sistema, la suya o la de consenso exterior.
Si generar un bloque tiene un alto coste computacional se garantiza que no sea rentable tratar de descomponer el sistema. De ahí viene el concepto de minado. Se construyen reglas de generación de los hash. Por ejemplo, se puede proponer que los hash siempre deben tener un número de ceros de comienzo. Para conseguirlo se tiene que sumar bytes aleatorios (lo que se llama nonce) al paquete de datos para obtener un hash que cumpla las características.
Proceso de minado
Como resumen: para que la red funcione es necesario que las transacciones se transmitan a todos los nodos, cada nodo intenta generar un hash que cumpla unas condiciones particulares (prueba de trabajo o proof-of-work) que se transmite a todos los nodos. Los nodos aceptan la prueba de trabajo y siguen trabajando en crear el siguiente bloque. De este modo, si hay gran cantidad de servidores que lleguen a un consenso y la capacidad de cálculo es muy elevada, probablemente distintos servidores encontrarán la clave correcta en distintos momentos, y será estadísticamente improbable que maliciosamente se pueda trabajar en contra del sistema por no poder competir con la capacidad de cálculo global y de consenso. El ganador del proceso de minado obtiene como premio un pago en la criptomoneda del sistema, lo que incentiva a que el sistema se mantenga a lo largo del tiempo.
Si os fijáis bien, el proceso de minado es una conversión, a riesgo (porque solo acierta uno primero), para la obtención de criptomonedas, de una amortización de la inversión en GPUs (tarjetas gráficas optimizadas para el cálculo matemático), del coste eléctrico de tener esas GPUs permanentemente funcionando y del coste de refrigeración del sistema (que no es banal).
Como ejemplo para entenderlo experimentalmente, en esta imagen podemos ver el hash generado con unos datos y un nonce comenzando en 0: https://andersbrownworth.com/blockchain/block
Obviamente es difícil que por casualidad salga un hash con cuatro ceros en el primer intento.
Podemos pulsar el botón de minar, es decir, ir modificando el nonce hasta que el hash que salga cumpla las condiciones deseadas de ceros iniciales. Obviamente podemos hacerlo como queramos, no tenemos que simplemente hacer crecer un contador sino utilizar el algoritmo que quieras.
Si dispones de matemáticos podrías construir sistemas distribuidos para que distintas personas se repartan el trabajo (recordad el proyecto SETI) y luego repartir beneficios en base a la contribución (que es posible que sea en modo más rentable de que un particular pueda participar en el minado).
Obviamente si un español quiere minar ahora (en un club de minado), con lo que se ha disparado la luz, las cuantas pueden no salir. Se me ocurre una idea: te vas a un pueblo en una zona fría, montas una instalación refrigerada por geotermia, instalas paneles solares y pones baterías… es posible que tengas siempre calefacción y agua caliente barata (las máquinas generan mucho calor estando a tope siempre) y que puedas amortizar la inversión a medio plazo.
Volviendo a nuestro ejemplo, veremos que con esa cadena base y un nonce progresivo han hecho falta 148.781 intentos para conseguir un hash con cuatro ceros.
Podemos escribir nuestro propio código en Python para jugar (donde ponemos la regla de que queremos un hash con 6 ceros), os pongo un ejemplo:
import hashlib from time import time sTextoBase="Con cien cañones por banda y viento en popa" encontradoNumeros = False contador = 0 tiempo_inicial = time() while (encontradoNumeros == False and contador < 100000000 ): contador = contador + 1 sBloque = sTextoBase + str(contador) if (contador % 5000000 == 0): print ("el contador es " + str(contador)) hash_hmd5 = hashlib.md5() hash_hmd5.update(sBloque.encode()) sRepresentacionHash = hash_hmd5.hexdigest() if (sRepresentacionHash[0:6] == "000000"): encontradoNumeros = True break print ("Fin de proceso " + str(contador) + " en " + str (time() - tiempo_inicial) + " segundos") if (encontradoNumeros == True): print ("El hash con 6 ceros de " + sBloque + " es " + sRepresentacionHash) else: print ("Mala suerte, no hemos logrado requisito de bloque")
En esta imagen podéis ver el código donde necesitamos más de 3 millones de intentos para obtener ese hash de 6 ceros.
Los bloques se van encadenando unos con otros y lo podéis ver en la siguiente imagen.
Red
En estos sistemas el riesgo puede ser que se constituya una red donde un solo actor tenga más del 51% de los servidores y pudiera defraudar al resto del sistema. Por eso, antes de invertir en una criptomoneda nueva (donde hay una red pequeña de servidores o nodos) hay que informarse un poquito de las características de la red para que tengamos ciertas garantías de no fraude.
Mecanismos de poda
Por último, para que el sistema no acabe comiendo muchos recursos hay que establecer mecanismos de poda de la base de datos para garantizar los bloques pero sin que el sistema continuamente se esté degradando en rendimiento.
Conclusión
Bueno, vista esta teoría base y jugado un poco con los conceptos, tendremos que hablar de otros temas interesantes como pueden ser usar la infraestructura de una moneda existente para crear otra moneda (en este caso no lo es exactamente sino un tokens) o introducir programática dentro de los datos, lo que se llaman contratos inteligentes.