Implementación de una cadena de bloques simple en Java

1. Información general

En este tutorial, aprenderemos los conceptos básicos de la tecnología blockchain. También implementaremos una aplicación básica en Java que se enfoca en los conceptos.

Además, discutiremos algunos conceptos avanzados y aplicaciones prácticas de esta tecnología.

2. ¿Qué es Blockchain?

Entonces, primero entendamos qué es exactamente blockchain ...

Bueno, tiene su origen en el documento técnico publicado por Satoshi Nakamoto sobre Bitcoin en 2008.

Blockchain es un libro mayor descentralizado de información . Consiste en bloques de datos conectados mediante el uso de criptografía. Pertenece a una red de nodos conectados a través de la red pública. Entenderemos esto mejor cuando intentemos crear un tutorial básico más adelante.

Hay algunos atributos importantes que debemos entender, así que vamos a repasarlos:

  • A prueba de manipulaciones: en primer lugar, los datos como parte de un bloque son a prueba de manipulaciones . Cada bloque está referenciado por un resumen criptográfico, comúnmente conocido como hash, lo que hace que el bloque sea a prueba de manipulaciones.
  • Descentralizado: toda la cadena de bloques está completamente descentralizada en toda la red. Esto significa que no hay ningún nodo maestro y todos los nodos de la red tienen la misma copia.
  • Transparente: Cada nodo que participa en la red valida y agrega un nuevo bloque a su cadena mediante consenso con otros nodos. Por lo tanto, cada nodo tiene una visibilidad completa de los datos.

3. ¿Cómo funciona Blockchain?

Ahora, entendamos cómo funciona blockchain.

Las unidades fundamentales de una cadena de bloques son los bloques . Un solo bloque puede encapsular varias transacciones u otros datos valiosos:

3.1. Minería de un bloque

Representamos un bloque por un valor hash. La generación del valor hash de un bloque se denomina "minar" el bloque. La extracción de un bloque suele ser computacionalmente costosa, ya que sirve como "prueba de trabajo".

El hash de un bloque normalmente consta de los siguientes datos:

  • Principalmente, el hash de un bloque consiste en las transacciones que encapsula
  • El hash también consta de la marca de tiempo de la creación del bloque.
  • También incluye un nonce, un número arbitrario utilizado en criptografía.
  • Finalmente, el hash del bloque actual también incluye el hash del bloque anterior

Varios nodos de la red pueden competir para extraer el bloque al mismo tiempo. Además de generar el hash, los nodos también deben verificar que las transacciones que se agregan en el bloque sean legítimas. ¡El primero en extraer un bloque gana la carrera!

3.2. Agregar un bloque a Blockchain

Si bien la extracción de un bloque es computacionalmente costosa, verificar que un bloque es legítimo es relativamente mucho más fácil . Todos los nodos de la red participan en la verificación de un bloque recién extraído.

Por lo tanto, un bloque recién extraído se agrega a la cadena de bloques según el consenso de los nodos.

Ahora, hay varios protocolos de consenso disponibles que podemos usar para la verificación. Los nodos de la red utilizan el mismo protocolo para detectar ramas maliciosas de la cadena. Por lo tanto, una rama maliciosa, incluso si se introduce, pronto será rechazada por la mayoría de los nodos.

4. Blockchain básico en Java

Ahora tenemos suficiente contexto para comenzar a construir una aplicación básica en Java.

Nuestro sencillo ejemplo aquí ilustrará los conceptos básicos que acabamos de ver. Una aplicación de nivel de producción implica muchas consideraciones que están más allá del alcance de este tutorial. Sin embargo, abordaremos algunos temas avanzados más adelante.

4.1. Implementar un bloque

En primer lugar, necesitamos definir un POJO simple que contendrá los datos de nuestro bloque:

public class Block { private String hash; private String previousHash; private String data; private long timeStamp; private int nonce; public Block(String data, String previousHash, long timeStamp) { this.data = data; this.previousHash = previousHash; this.timeStamp = timeStamp; this.hash = calculateBlockHash(); } // standard getters and setters }

Entendamos lo que hemos empaquetado aquí:

  • Hash del bloque anterior, parte importante para construir la cadena
  • Los datos reales, cualquier información que tenga valor, como un contrato.
  • La marca de tiempo de la creación de este bloque
  • Un nonce, que es un número arbitrario utilizado en criptografía.
  • Finalmente, el hash de este bloque, calculado en base a otros datos

4.2. Calculando el hash

Ahora bien, ¿cómo calculamos el hash de un bloque? Hemos utilizado un método calculateBlockHash pero aún no hemos visto una implementación. Antes de implementar este método, vale la pena dedicar un tiempo a comprender qué es exactamente un hash.

Un hash es una salida de algo conocido como función hash. Una función hash asigna datos de entrada de tamaño arbitrario a datos de salida de tamaño fijo . El hash es bastante sensible a cualquier cambio en los datos de entrada, por pequeño que sea.

Además, es imposible recuperar los datos de entrada solo de su hash. Estas propiedades hacen que la función hash sea bastante útil en criptografía.

Entonces, veamos cómo podemos generar el hash de nuestro bloque en Java:

public String calculateBlockHash() { String dataToHash = previousHash + Long.toString(timeStamp) + Integer.toString(nonce) + data; MessageDigest digest = null; byte[] bytes = null; try { digest = MessageDigest.getInstance("SHA-256"); bytes = digest.digest(dataToHash.getBytes(UTF_8)); } catch (NoSuchAlgorithmException | UnsupportedEncodingException ex) { logger.log(Level.SEVERE, ex.getMessage()); } StringBuffer buffer = new StringBuffer(); for (byte b : bytes) { buffer.append(String.format("%02x", b)); } return buffer.toString(); }

Aquí están sucediendo muchas cosas, vamos a entenderlas en detalle:

  • Primero, concatenamos diferentes partes del bloque para generar un hash desde
  • Luego, obtenemos una instancia de la función hash SHA-256 de MessageDigest
  • Luego, generamos el valor hash de nuestros datos de entrada, que es una matriz de bytes
  • Finalmente, transformamos la matriz de bytes en una cadena hexadecimal, un hash se representa normalmente como un número hexadecimal de 32 dígitos

4.3. ¿Ya hemos minado el bloque?

Todo suena simple y elegante hasta ahora, excepto por el hecho de que aún no hemos extraído el bloque. Entonces, ¿qué implica exactamente extraer un bloque, que ha cautivado la imaginación de los desarrolladores desde hace algún tiempo?

Bueno, extraer un bloque significa resolver una tarea computacionalmente compleja para el bloque. Si bien calcular el hash de un bloque es algo trivial, encontrar el hash que comienza con cinco ceros no lo es. Aún más complicado sería encontrar un hash que comience con diez ceros, y tenemos una idea general.

Entonces, ¿cómo podemos hacer esto exactamente? Honestamente, ¡la solución es mucho menos elegante! Es con la fuerza bruta que intentamos lograr este objetivo. Hacemos uso de nonce aquí:

public String mineBlock(int prefix) { String prefixString = new String(new char[prefix]).replace('\0', '0'); while (!hash.substring(0, prefix).equals(prefixString)) { nonce++; hash = calculateBlockHash(); } return hash; }

Veamos qué estamos tratando de hacer aquí:

  • Comenzamos definiendo el prefijo que deseamos encontrar
  • Luego comprobamos si hemos encontrado la solución.
  • Si no, incrementamos el nonce y calculamos el hash en un bucle
  • El ciclo continúa hasta que logramos el premio gordo

Comenzamos con el valor predeterminado de nonce aquí y lo incrementamos en uno. Pero existen estrategias más sofisticadas para iniciar e incrementar un nonce en aplicaciones del mundo real. Además, aquí no verificamos nuestros datos, lo que suele ser una parte importante.

4.4. Ejecutemos el ejemplo

Ahora que tenemos nuestro bloque definido junto con sus funciones, podemos usar esto para crear una cadena de bloques simple. Almacenaremos esto en una ArrayList :

List blockchain = new ArrayList(); int prefix = 4; String prefixString = new String(new char[prefix]).replace('\0', '0');

Además, hemos definido un prefijo de cuatro, lo que efectivamente significa que queremos que nuestro hash comience con cuatro ceros.

Veamos cómo podemos agregar un bloque aquí:

@Test public void givenBlockchain_whenNewBlockAdded_thenSuccess() { Block newBlock = new Block( "The is a New Block.", blockchain.get(blockchain.size() - 1).getHash(), new Date().getTime()); newBlock.mineBlock(prefix); assertTrue(newBlock.getHash().substring(0, prefix).equals(prefixString)); blockchain.add(newBlock); }

4.5. Verificación de blockchain

¿Cómo puede un nodo validar que una cadena de bloques es válida? Si bien esto puede ser bastante complicado, pensemos en una versión simple:

@Test public void givenBlockchain_whenValidated_thenSuccess() { boolean flag = true; for (int i = 0; i < blockchain.size(); i++) { String previousHash = i==0 ? "0" : blockchain.get(i - 1).getHash(); flag = blockchain.get(i).getHash().equals(blockchain.get(i).calculateBlockHash()) && previousHash.equals(blockchain.get(i).getPreviousHash()) && blockchain.get(i).getHash().substring(0, prefix).equals(prefixString); if (!flag) break; } assertTrue(flag); }

Entonces, aquí estamos haciendo tres verificaciones específicas para cada bloque:

  • El hash almacenado del bloque actual es en realidad lo que calcula
  • El hash del bloque anterior almacenado en el bloque actual es el hash del bloque anterior
  • El bloque actual ha sido minado

5. Algunos conceptos avanzados

Si bien nuestro ejemplo básico resalta los conceptos básicos de una cadena de bloques, ciertamente no está completo. Para poner esta tecnología en uso práctico, se deben tener en cuenta varias otras consideraciones.

Si bien no es posible detallarlos todos, repasemos algunos de los importantes:

5.1. Verificación de transacciones

Calculating the hash of a block and finding the desired hash is just one part of mining. A block consists of data, often in the form of multiple transactions. These must be verified before they can be made part of a block and mined.

A typical implementation of blockchain sets a restriction on how much data can be part of a block. It also sets up rules on how a transaction can be verified. Multiple nodes in the network participate in the verification process.

5.2. Alternate Consensus Protocol

We saw that consensus algorithm like “Proof of Work” is used to mine and validate a block. However, this is not the only consensus algorithm available for use.

There are several other consensus algorithms to choose from, like Proof of Stake, Proof of Authority, and Proof of Weight. All of these have their pros and cons. Which one to use depends upon the type of application we intend to design.

5.3. Mining Reward

A blockchain network typically consists of voluntary nodes. Now, why would anyone want to contribute to this complex process and keep it legit and growing?

This is because nodes are rewarded for verifying the transactions and mining a block. These rewards are typically in the form of coin associated with the application. But an application can decide the reward to be anything of value.

5.4. Node Types

A blockchain completely relies on its network to operate. In theory, the network is completely decentralized, and every node is equal. However, in practice, a network consists of multiple types of nodes.

While a full node has a complete list of transactions, a light node only has a partial list. Moreover, not all nodes participate in verification and validation.

5.5. Secure Communication

One of the hallmarks of blockchain technology is its openness and anonymity. But how does it provide security to transactions being carried within? This is based on cryptography and public key infrastructure.

The initiator of a transaction uses their private key to secure it and attach it to the public key of the recipient. Nodes can use the public keys of the participants to verify transactions.

6. Practical Applications of Blockchain

So, blockchain seems to be an exciting technology, but it also must prove useful. This technology has been around for some time now and – needless to say – it has proved to be disruptive in many domains.

Its application in many other areas is being actively pursued. Let's understand the most popular applications:

  • Currency: This is by far the oldest and most widely known use of blockchain, thanks to the success of Bitcoin. They provide secure and frictionless money to people across the globe without any central authority or government intervention.
  • Identity: Digital identity is fast becoming the norm in the present world. However, this is mired by security issues and tampering. Blockchain is inevitable in revolutionizing this area with completely secure and tamper-proof identities.
  • Healthcare: Healthcare industry is loaded with data, mostly handled by central authorities. This decreases transparency, security, and efficiency in handling such data. Blockchain technology can provide a system without any third party to provide much-needed trust.
  • Government: This is perhaps an area which is well open to disruption by the blockchain technology. Government is typically at the center of several citizen services which are often laden with inefficiencies and corruption. Blockchain can help establish much better government-citizen relations.

7. Tools of the Trade

While our basic implementation here is useful to elicit the concepts, it's not practical to develop a product on blockchain from scratch. Thankfully, this space has matured now, and we do have some quite useful tools to start from.

Let's go through some of the popular tools to work within this space:

  • Solidity: Solidity is a statically-typed and object-oriented programming language designed for writing smart contracts. It can be used to write smart contracts on various blockchain platforms like Ethereum.
  • Remix IDE: Remix is a powerful open-source tool to write smart contracts in Solidity. This enables the user to write smart contracts right from the browser.
  • Truffle Suite: Truffle provides a bunch of tools to get a developer up and started in developing distributed apps. This includes Truffle, Ganache, and Drizzle.
  • Ethlint/Solium: Solium allows developers to ensure that their smart contracts written on Solidity is free from style and security issues. Solium also helps in fixing these issues.
  • Paridad: la paridad ayuda a configurar el entorno de desarrollo para el contrato inteligente en Etherium. Proporciona una forma rápida y segura de interactuar con la cadena de bloques.

8. Conclusión

En resumen, en este tutorial, analizamos los conceptos básicos de la tecnología blockchain. Entendimos cómo una red mina y agrega un nuevo bloque en la cadena de bloques. Además, implementamos los conceptos básicos en Java. También discutimos algunos de los conceptos avanzados relacionados con esta tecnología.

Finalmente, terminamos con algunas aplicaciones prácticas de blockchain y herramientas disponibles.

Como siempre, el código se puede encontrar en GitHub.