Recompensas de transacciones y minería (Javascript blockchain, parte 3)

original: https://www.savjee.be/2018/02/Transactions-and-mining-rewards/


Esta es la parte 3 de mi serie de publicaciones de blog en la que creamos una cadena de bloques en Javascript. En las publicaciones de blog anteriores, creamos una cadena de bloques simple e implementamos una prueba de trabajo para protegerla de los spammers y los atacantes. Sin embargo, hicimos algunos atajos en el camino: nuestra cadena de bloques solo puede almacenar 1 transacción en un bloque y no hay recompensas para los mineros. ¡Arreglemos eso!

Reestructuración de la clase Block

En este momento, un bloque tiene las propiedades index, previousHash, timestamp, data, hash y nonce. La propiedad del index no es realmente útil, de hecho, ni siquiera sé por qué lo agregué para empezar. Entonces, eliminemos eso y cambiemos el nombre de los data a transactions que tengan más sentido.
 class Block { constructor ( timestamp , transactions , previousHash = '' ) { this . previousHash = previousHash ; this . timestamp = timestamp ; this . transactions = transactions ; this . hash = this . calculateHash (); this . nonce = 0 ; } } 
Cuando cambiamos nuestra clase Block, también tenemos que cambiar su función calculateHash() . En este momento, todavía utiliza las antiguas propiedades de index y data , que acabamos de eliminar.
 calculateHash () { return SHA256 ( this . previousHash + this . timestamp + JSON . stringify ( this . transactions ) + this . nonce ). toString (); } 

Clase de transacción

Dentro de un bloque podremos almacenar múltiples transacciones. Así que definamos también una clase de Transaction para que podamos bloquear las propiedades que debe tener una transacción:
 class Transaction { constructor ( fromAddress , toAddress , amount ){ this . fromAddress = fromAddress ; this . toAddress = toAddress ; this . amount = amount ; } } 
En este ejemplo, una transacción será muy simple, solo contendrá un remitente ( fromAddress ) un receptor ( toAddress ) y una cantidad. Si es necesario, puede agregar más campos a una transacción, pero estos son el mínimo absoluto.

Adaptando nuestra Blockchain

Ahora viene la tarea más grande de todas: hacer que nuestro Blockchainfuncione con todos estos nuevos cambios. Lo primero que necesitamos es un lugar para almacenar transacciones pendientes.
Como sabe, las cadenas de bloques crean bloques en un intervalo constante gracias al algoritmo de prueba de trabajo. En el caso de Bitcoin, la dificultad se ajusta para que se creen nuevos bloques aproximadamente cada 10 minutos. Sin embargo, debería ser posible enviar nuevas transacciones entre la creación de dos bloques.
Entonces, para hacer eso, comencemos cambiando nuestro constructor de Blockchain para que tenga un lugar donde almacenar las transacciones pendientes. También crearemos una propiedad que defina cuántas monedas recibe un minero como recompensa:
 class Blockchain { constructor () { this . chain = [ this . createGenesisBlock ()]; this . difficulty = 5 ; // Place to store transactions in between block creation this . pendingTransactions = []; // How many coins a miner will get as a reward for his/her efforts this . miningReward = 100 ; } } 
A continuación, tenemos que adaptar nuestro método addBlock() y al adaptarlo quiero decir eliminarlo por completo para volver a escribirlo. No permitiremos que las personas agreguen bloques directamente a nuestra cadena. En su lugar, tienen que agregar transacciones que se incluirán en el siguiente bloque. Así que reemplazaremos el método addBlock() con createTransaction() , que tiene más sentido:
 createTransaction ( transaction ) { // There should be some validation here! // Push into onto the "pendingTransactions" array this . pendingTransactions . push ( transaction ); } 

Bloques mineros

La gente ahora puede agregar nuevas transacciones a la lista de pendientes.Pero de una manera u otra, tenemos que eliminarlos y ponerlos dentro de bloques reales. Entonces, para hacer eso, minePendingTransactions() un método minePendingTransactions() . Este método no solo extraerá un nuevo bloque con todas las transacciones pendientes, sino que también enviará una recompensa minera al minero.
 minePendingTransactions ( miningRewardAddress ) { // Create new block with all pending transactions and mine it.. let block = new Block ( Date . now (), this . pendingTransactions ); block . mineBlock ( this . difficulty ); // Add the newly mined block to the chain this . chain . push ( block ); // Reset the pending transactions and send the mining reward this . pendingTransactions = [ new Transaction ( null , miningRewardAddress , this . miningReward ) ]; } 
Tenga en cuenta que el método toma un argumento miningRewardAddress. Si comienza a extraer, puede pasar su dirección de billetera a este método.Una vez que haya extraído un bloque con éxito, el sistema creará una nueva transacción para darle su recompensa minera (en este caso 100 monedas).
Una cosa a tener en cuenta es que en esta implementación tomamos todas las transacciones pendientes y las agregamos a un bloque. En realidad, sin embargo, eso no funcionará porque el tamaño de un bloque es limitado. En el caso de Bitcoin, hay un límite de tamaño de bloque de 2 mb. Si hay más transacciones que pueden caber en un bloque, el minero puede elegir qué transacción incluye y cuál no (generalmente ganan las que tienen la tarifa más alta).

Balance de una dirección

Antes de que podamos probar nuestro código, ¡hagamos una cosa más! Sería bueno poder verificar los saldos de las direcciones en nuestra cadena de bloques.
 getBalanceOfAddress ( address ){ let balance = 0 ; // you start at zero! // Loop over each block and each transaction inside the block for ( const block of this . chain ){ for ( const trans of block . transactions ){ // If the given address is the sender -> reduce the balance if ( trans . fromAddress === address ){ balance -= trans . amount ; } // If the given address is the receiver -> increase the balance if ( trans . toAddress === address ){ balance += trans . amount ; } } } return balance ; } 

Probándolo

¡Bien, hemos terminado y finalmente podemos probar si todo está funcionando! Para hacer eso, creemos algunas transacciones:
 let savjeeCoin = new Blockchain (); console . log ( 'Creating some transactions...' ); savjeeCoin . createTransaction ( new Transaction ( 'address1' , 'address2' , 100 )); savjeeCoin . createTransaction ( new Transaction ( 'address2' , 'address1' , 50 )); 
Estas transacciones están ahora pendientes y para que se confirmen, tenemos que iniciar el minero:
 console . log ( 'Starting the miner...' ); savjeeCoin . minePendingTransactions ( 'xaviers-address' ); 
Cuando iniciamos el minero, también pasamos una dirección en la que queremos recibir la recompensa minera. En este caso, mi dirección es xaviers-address (¡bastante complicada!)
Después de eso, xaviers-address el saldo de xaviers-address :
 console . log ( 'Balance of Xaviers address is' , savjeeCoin . getBalanceOfAddress ( 'xaviers-address' )); // Output: 0 
Muestra que mi saldo es cero. ¿Esperar lo? ¿No debería haber obtenido mi recompensa minera? Bueno, si miras detenidamente el código, verás que el sistema crea un nuevo bloque y luego agrega tus recompensas mineras como una nueva transacción pendiente. Esa transacción se incluirá en el siguiente bloque. Entonces, si iniciamos de nuevo al minero, ¡recibiremos nuestra recompensa de 100 monedas!
 console . log ( 'Starting the miner again!' ); savjeeCoin . minePendingTransactions ( "xaviers-address" ); console . log ( 'Balance of Xaviers address is' , savjeeCoin . getBalanceOfAddress ( 'xaviers-address' )); // Output: 100 

Limitaciones y conclusión

En este momento, nuestra pequeña cadena de bloques puede almacenar múltiples transacciones en un bloque y otorgar recompensas a los mineros.
Sin embargo, todavía faltan algunas cosas: al enviar dinero no verificamos si el remitente tiene saldo suficiente para realizar esa transacción. Sin embargo, esto es algo fácil de abordar. Tampoco tenemos una forma de crear una nueva billetera y firmar transacciones (tradicionalmente eso se haría con encriptación de clave pública / privada)

Descargo de responsabilidad y código fuente

Quiero señalar que esto de ninguna manera es una implementación completa de blockchain. Todavía carece de muchas características. Esto es solo una prueba de concepto diseñada para ayudarlo a comprender cómo funcionan las cadenas de bloques internamente.
El código fuente de este proyecto está disponible en GitHub .
Hora de Libertad

Post a Comment

Previous Post Next Post