Firmando transacciones (javascript blockchain, parte 4)


Fuente original: https://www.savjee.be/2018/10/Signing-transactions-blockchain-javascript/


Creando un generador de claves

Para resolver este problema tenemos que firmar transacciones. Lo hacemos con un par de llaves público y privado. La clave pública se usará como la dirección de nuestra billetera y se puede compartir libremente, mientras que la clave privada se utilizará para firmar transacciones. Esto significa que solo podemos gastar dinero en una billetera si tenemos la clave privada asociada.El mismo sistema se utiliza en Bitcoin, Euthereum y otras criptomonedas.
Así que vamos a empezar generándonos una clave pública y privada.keygenerator.js un archivo llamado keygenerator.js para eso:

 // Import the elliptic library and initialize a curve. // You can use other curves if you want. const EC = require ( 'elliptic' ). ec ; const ec = new EC ( 'secp256k1' ); // Generate a new key pair and convert them to hex-strings const key = ec . genKeyPair (); const publicKey = key . getPublic ( 'hex' ); const privateKey = key . getPrivate ( 'hex' ); // Print the keys to the console console . log (); console . log ( 'Your public key:' , publicKey ); console . log (); console . log ( 'Your private key' , privateKey ); 

Usamos la biblioteca elíptica para generar un par de llaves. También tenemos que instalar el paquete:
 npm install elliptic 
Ahora vamos a ejecutarlo!
 node keygenerator.js 
El script devolverá una clave pública y privada. Anótelos, se usarán como la dirección de su billetera y como una forma de obtener fondos de su billetera.
 Your public key: 0481758cb017885d884d1a8eb309c82e2644bc1776a0244b000adef2bb05755e8bbca68905b1387cf2e97b044a4287befa9400c1bd6c2ee6bf1241341ab4338f7a Your private key: 854de2a5ab09aa1ed51fd878a917c9778f606ca010effb7bc488c643744b9a38 

Cambiar clase de transacción

Ahora tenemos que adaptar nuestra clase de Transaction . Agregaremos un método que nos permita firmar una transacción, verificar la firma y también vamos a calcular el hash de las transacciones.
Vamos a empezar con el hash:

 calculateHash (){ return SHA256 ( this . fromAddress + this . toAddress + this . amount ) . toString (); } 

¿Por qué necesitamos calcular un hash para cada transacción? Bueno, porque no queremos firmar todos los datos en el objeto Transacción. Solo vamos a firmar el hash de la transacción.
A continuación, vamos a crear un método signTransaction , que debe aceptar signingKey como parámetro.

 signTransaction ( signingKey ){ if ( signingKey . getPublic ( 'hex' ) !== this . fromAddress ){ throw new Error ( 'You cannot sign transactions for other wallets!' ); } const hashTx = this . calculateHash (); const sig = signingKey . sign ( hashTx , 'base64' ); this . signature = sig . toDER ( 'hex' ); } 

También agregamos un cheque para verificar que la clave dada coincida con el remitente de la transacción. Recuerde: solo puede firmar transacciones cuando salen de su propio bolsillo. No puedes gastar las monedas de otra persona.
Finalmente, podemos agregar un método isValid que verificará la firma en la transacción y devolverá true si todo es correcto o false si alguien ha intentado manipular una transacción y la firma no es válida:

 isValid (){ if ( this . fromAddress === null ) return true ; if ( ! this . signature || this . signature . length === 0 ){ throw new Error ( 'No signature in this transaction' ); } const publicKey = ec . keyFromPublic ( this . fromAddress , 'hex' ); return publicKey . verify ( this . calculateHash (), this . signature ); } 

Clase de bloque

Para poner una transacción en una cadena de bloques, debe agregarla a un Bloque. Un bloque puede contener múltiples transacciones, por lo que para hacer nuestras vidas un poco más fáciles, haré un método simple que compruebe si todas las transacciones dentro de un bloque son válidas y están firmadas correctamente.
Simplemente isValid todas las transacciones y llamamos a su método isValid :

 hasValidTransactions (){ for ( const tx of this . transactions ){ if ( ! tx . isValid ()){ return false ; } } return true ; } 

Eso es todo para la clase Block. ¡Ahora pasemos a nuestra gran clase de Blockchain!

Clase blockchain

Finalmente tenemos que adaptar nuestra clase Blockchain.
Comenzaremos por cambiar el método isChainValid . En este momento, observa todos los bloques y verifica que todos apuntan hacia el bloque anterior correcto. Podemos mantener todos esos cheques, pero también tenemos que verificar si el bloque contiene transacciones válidas y firmadas.

 isChainValid (){ // .... for ( let i = 1 ; i < this . chain . length ; i ++ ) { const currentBlock = this . chain [ i ]; const previousBlock = this . chain [ i - 1 ]; // ... if ( ! currentBlock . hasValidTransactions ()) { return false ; } } } 

¡Podemos usar el método hasValidTransactions que acabamos de agregar a nuestra clase Block! ¡Conveniente!
Entonces también tenemos que cambiar nuestro método createTransaction . Comenzaré por cambiarle el nombre a addTransaction porque eso tiene más sentido. El método no crea una transacción, solo acepta un objeto de Transaction que el usuario le da.
A continuación, debemos asegurarnos de que un usuario solo pueda agregar una transacción válida a nuestra cadena de bloques. Eso significa verificar si las direcciones from y to se completan y que la transacción se ha firmado correctamente:

 addTransaction ( transaction ){ if ( ! transaction . fromAddress || ! transaction . toAddress ){ throw new Error ( 'Transaction must include from and to address' ); } if ( ! transaction . isValid ()){ throw new Error ( 'Cannot add invalid transaction to chain' ); } this . pendingTransactions . push ( transaction ); } 

¡Y eso es todo lo que tenemos que hacer!

Probando todo!

Estamos listos para probar nuestra nueva implementación. Comencemos importando la clave privada que generamos al comienzo de esta publicación:

 // Import elliptic const EC = require ( 'elliptic' ). ec ; const ec = new EC ( 'secp256k1' ); // Create key object const myKey = ec . keyFromPrivate ( '7c4c45907dec40c91bab3480c39032e90049f1a44f3e18c3e07c23e3273995cf' ); const myWalletAddress = myKey . getPublic ( 'hex' ); 

Una vez que tengamos nuestra clave, ¡podemos crear una nueva instancia de Blockchain y realizar una transacción! En este caso, soy el único en la red, así que solo enviaré mi dinero a una clave pública aleatoria. Sin embargo, tenga en cuenta que al hacer esto, sus monedas quedarán guardadas para siempre en esa dirección.

 // Create new instance of Blockchain class const savjeeCoin = new Blockchain (); // Make a transaction const tx1 = new Transaction ( myWalletAddress , 'public key of recipient' , 10 ); tx1 . signTransaction ( myKey ); savjeeCoin . addTransaction ( tx1 ); // Mine block savjeeCoin . minePendingTransactions ( myWalletAddress ); 

Después de que extrajimos un nuevo bloque, podemos verificar nuestro saldo al darle al método nuestra clave pública:

 console . log ( 'Balance of xavier is' , savjeeCoin . getBalanceOfAddress ( myWalletAddress )); 

Esto informará que el saldo en mi billetera es de 90. Eso se debe a que recibo 100 monedas por extraer un nuevo bloque (recompensa de minería) y gasté 10 monedas al enviar una transacción.

A prueba de manipulaciones

Al igual que antes, nuestro Blockchain permanece a prueba de manipulaciones. De hecho, podría decir que es aún más resistente ahora porque requerimos que las transacciones se firmen con una clave privada.

 // Tampering savjeeCoin . chain [ 1 ]. transactions [ 0 ]. amount = 10 ; // Check if the chain is valid console . log (); console . log ( 'Blockchain valid?' , savjeeCoin . isChainValid () ? 'Yes' : 'No' ); 
 // Tampering savjeeCoin . chain [ 1 ]. transactions [ 0 ]. amount = 10 ; // Check if the chain is valid console . log (); console . log ( 'Blockchain valid?' , savjeeCoin . isChainValid () ? 'Yes' : 'No' ); 

Limitaciones y conclusión

Este blockchain tiene algunas limitaciones. Todavía te permite gastar más monedas que tienes en tu billetera y no tiene una red P2P. ¡Mas para seguir!

Descargo de responsabilidad y código fuente

Esto de ninguna manera es una implementación completa de blockchain! Solo tiene fines educativos, para comprender cómo funciona un blockchain a nivel técnico.
El código fuente de este proyecto está disponible en GitHub .

Hora de Libertad

Post a Comment

Previous Post Next Post