Seguro que últimamente has escuchado la palabra Bitcoin o Blockchain, en las noticias, en el periódico o incluso a algún familiar. No te preocupes si no sabes muy bien de qué están hablando, hoy te contaremos qué es, para qué sirve y haremos una demostración de una Blockchain en Swift.
Blockchain, block y chain
Para empezar a definir una Blockchain hemos de entender a qué se está refiriendo. Sabiendo un poco de inglés vemos que es la traducción literal de ‘cadena de bloques’, y, exactamente eso es lo que es.
Al fin y al cabo, una Blockchain no es más que información dividida en bloques de un tamaño definido (blocks) y conectados entre ellos, haciendo una cadena (chain).
Cada uno de los bloques contiene una información determinada y un campo especial llamado hash. Un hash no es más que una ‘palabra’ que deriva del contenido de cada bloque. En la imagen, vemos el bloque con index 56, su hash es ‘4bac273…’. Dicho hash es una combinación de los datos contenidos en ese bloque.
Cada bloque dentro de la cadena contiene la información que previamente hemos dicho, así como su propio hash y el hash del bloque anterior al qué está conectado.
¿Qué pasa si alguien modifica la información de un bloque?
Si queremos modificar la información de uno de los bloques ya existentes en la cadena, el hash generado por la nueva información no coincidirá con el hash almacenado en la cadena posterior, por tanto, la cadena se romperá.
Es posible modificar los datos de un bloque, pero, el propósito de una Blockchain es residir en los miles de dispositivos que forman dicha cadena. Al acceder a la cadena de bloques, el programa que utilices para ello, se descargará toda la información de la cadena, replicando bloque a bloque en tu propio ordenador. Tu podrás modificar los datos de uno de los bloques, pero la propia cadena descartará tu cambio, ya que la mayoría de los dispositivos conectados a la cadena tienen la versión sin modificar de ésta y, en una blockchain, reina la mayoría.
Por último, comentar que existen cadenas públicas (Bitcoin, Ethereum, Litecoin, …) o de uso privado. En este post te mostraremos como funciona una cadena de bloques de manera básica construyendo una utilizando Swift.
Empecemos: Creando nuestros bloques.
Este tutorial presupone que el lector tiene conocimientos básicos de programación, así como nociones básicas de Swift. Utilizaremos Swift 4 y Xcode 9.3 para desarrollar este ejemplo.
Primero de todo necesitamos ver e implementar nuestra clase Block. Esta será la clase que almacenará toda la información de nuestro bloque dentro de la cadena.
struct Block: Codable {
let index: Int let timestamp: Double let transactions: [Transaction]
let proof: Int let previousHash: Data // MARK: - Generamos el hash para este bloque
func hash() -> Data {
let encoder = JSONEncoder()
let data = try! encoder.encode(self)
return data.sha256()
}
// MARK: - Información básica acerca de este bloque
func description() -> String {
return "Bloque #\(index) (creado el \(timestamp)), con \(transactions.count) transacciones"
}
init(index: Int, transactions: [Transaction], proof: Int, previousHash: Data) {
self.index = index
self.transactions = transactions
self.proof = proof
self.previousHash = previousHash
// Generamos el timestamp para este bloque
self.timestamp = Date().timeIntervalSince1970
}
}
index: Este no es más que la posición de nuestro bloque en la cadena.
timestamp: Este campo nos indica la fecha de creación de nuestro bloque en formato Unix.
transactions: Array de objetos de la clase Transaction. Más tarde veremos más acerca de este campo.
proof: Valor que nos servirá para crear el hash de nuestro bloque.
hash: Método que genera el hash con la información de nuestro bloque.
previousHash: El valor del hash del bloque anterior.
Necesitaremos esta extensión para poder implementar todas las funcionalidades de nuestro bloque, en los pasos siguientes veremos para qué sirve.
extension Data {
func sha256() -> Data {
guard let res = NSMutableData(length: Int(CC_SHA256_DIGEST_LENGTH)) else { fatalError() }
CC_SHA256((self as NSData).bytes, CC_LONG(self.count), res.mutableBytes.assumingMemoryBound(to: UInt8.self))
return res as Data
}
func hexDigest() -> String {
return self.map({ String(format: "%02x", $0) }).joined()
}
}
Creemos nuestras transacciones.
Una blockchain se puede utilizar para infinidad de propósitos. Las más conocidas son las monedas virtuales, pero pueden servir para contratos inteligentes o almacenar escrituras de propiedades. Puedes ver una blockchain como una base de datos donde su información no está controlada por nadie, no se puede modificar por nadie una vez está dentro de la cadena y todo el mundo tiene acceso para consultar dicha información.
En este ejemplo simple, seguiremos la idea de una criptomoneda.
class Transaction: Codable {
let sender: String let recipient: String let amount: Int init(sender: String, recipient: String, amount: Int) {
self.sender = sender
self.recipient = recipient
self.amount = amount
}
}
sender: Persona que envía dinero.
recipient: Persona que recibe el dinero.
amount: Cantidad de dinero a percibir.
Sigamos: Ahora nuestra cadena.
Nuestra cadena será la encargada de almacenar los distintos bloques en ella. En este ejemplo simple, únicamente veremos cómo añadir un bloque a la cadena, no nos centraremos en procesos más avanzados como la proof of work, el mining o la validación de los bloques.
class Blockchain {
private var pendingTransactions: [Transaction] = []
var ourChain: [Block] = []
init() {
createBlock(proof: 80, previousHash: "0".data(using: .utf8))
}
func createBlock(proof: Int, previousHash: Data? = nil) -> Block {
let prevHash: Data if let previousHash = previousHash {
prevHash = previousHash
} else {
prevHash = getLastBlock().hash()
}
let block = Block(index: ourChain.count, transactions: pendingTransactions, proof: proof, previousHash: prevHash)
pendingTransactions.removeAll() ourChain.append(block)
return block
}
func createTransaction(sender: String, recipient: String, amount: Int) -> Int {
let transaction = Transaction(sender: sender, recipient: recipient, amount: amount) pendingTransactions.append(transaction)
return getLastBlock().index + 1 }
func getLastBlock() -> Block {
guard let last = ourChain.last else {
fatalError("Nuestra cadena ha de contener, al menos, un bloque original.") }
return last
}
// MARK: - Algoritmo simple de validación de bloques
class func proofOfWork(lastProof: Int) -> Int {
var proof: Int = 0 while !validProof(lastProof: lastProof, proof: proof) {
proof += 1 }
return proof
}
class func validProof(lastProof: Int, proof: Int) -> Bool {
guard let result = String("\(lastProof)\(proof)").data(using: .utf8) else {
fatalError()
}
let result_hash = result.sha256().hexDigest()
return result_hash.prefix(4) == "0000" }
}
ourChain: Será el array de bloques que tendrá nuestra cadena.
El método createTransaction crea una nueva transacción y la añade al siguiente bloque de la cadena, a la espera de que se mine el bloque para que se incorpore en nuestra blockchain.
El método createNewBlock nos sirve para añadir un nuevo bloque dentro de nuestra cadena. Éste cogerá el bloque anterior para asignar el hash de éste al campo previousHash del nuevo bloque a añadir.
Por último, el método proofOfWork, creará el nuevo hash para el bloque que queremos añadir a nuestra cadena y generará una transacción de recompensa para la persona que consiga generar dicho hash. Este proceso de mining se puede ver mejor en el ejemplo que se muestra al final de esta guía.
¡Ya has implementado tu primera blockchain! Ahora puedes ver el proyecto completo, con los algoritmos de Proof-of-Work y validación de bloques. Puedes descargar un ejemplo de cómo monta runa blockchain aquí.
Si tienes cualquier duda, quieres crear un proyecto basado en la Blockchain o necesitas asesoramiento para lanzar tu proyecto, contacta con nosotros ahora y te ayudaremos.
Dribba, the mobile agency. Agencia de desarrollo de tecnologías mobile en Barcelona y Zurich. Desarrollamos apps nativas iOS y Android, para multinacionales y startups de todo el mundo. Consulta nuestros servicios tanto en desarrollo, diseño como consultoría mobile y tecnológica.
Comments