Resoluciones del Nuevo Mes: Septiembre 2016

Otro mes de trabajo intensivo en @RSKsmart, es tiempo de escribir las resoluciones personales para el nuevo mes. Primero, reviso las del mes pasado:

– Mejorar CrysSharp [completo] ver repo
– Mejorar CrysJS [pendiente]
– Mejorar BlockchainSharp [pendiente]
– Mejorar SimpleBlockchain [pendiente]
– Comenzar Solidity Compiler [completo] ver repo

También estuve trabajando en:

– Mejorar SimpleDSL [completo] ver repo
– Comenzar ChineseP, sitio de práctica de chino, en in NodeJS [completo] ver repo

Las resoluciones para el nuevo mes:

– Mejorar CrysSharp
– Mejorar BlockchainSharp
– Mejorar SimpleBlockchain
– Continuar Solidity Compiler
– Continuar ChineseP

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted in C#, JavaScript, NodeJs, Proyectos Open Source | Leave a comment

Resoluciones del Nuevo Mes: Agosto 2016

Julio ha sido un mes de bastante ocupación en mi trabajo diario de desarrollo de software. Pero igual me hice algo de tiempo para trabajar en proyectos personales. Revisión de mis resoluciones del mes pasado:

– Mejorar WangTiles [pendiente]
– Mejorar WangTilesJS [pendiente]
– Mejorar CrysSharp [completo] ver repo
– Mejorar CrysJS [completo] ver repo
– Mejorar SimpleForth [pendiente]
– Mejorar BlockchainSharp [completo] ver repo
– Mejorar SimpleBlockchain [completo] ver repo

Tambien estuve trabajando en:

– Comenzar ChineseP, un sitio de práctica de idioma chino [completo] ver repo
– Actualizar SimpleLists [completo] ver repo

Mis resoluciones para el nuevo mes de agosto:

– Mejorar CrysSharp
– Mejorar CrysJS
– Mejorar BlockchainSharp
– Mejorar SimpleBlockchain
– Comenzar Solidity Compiler

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted in Blockchain, C#, JavaScript, NodeJs, Proyectos Open Source | Leave a comment

Armando una Blockchain (14)

Anterior Post

Despues de un tiempo de descanso, estoy de vuelta, trabajando en mis proyectos personales de blockchain:

https://github.com/ajlopez/SimpleBlockchain
https://github.com/ajlopez/BlockchainSharp

Hoy quiero presentar mis primeros tests para modelar un minero. Un minero debe minar bloques, agregando transacciones, armando un bloque hijo del mejor bloque de la blockchain. Hay varios casos a resolver: las transacciones deben ser válidas, deben ser minadas una sola vez, etc…. Pero siguiendo el flujo de trabajo de TDD (Test-Driven Development), puedo ir agregando funcionalidad guiado por esos tests. El primero:

exports['mine empty block'] = function (test) {
    var txs = transactions.txs();
    var miner = miners.miner(txs);
    
    var states = tries.states();
    var genesis = blocks.block();
    
    var result = miner.mine(genesis, states);
    
    test.ok(result);
    test.ok(result.hash);
    test.ok(result.transactions);
    test.ok(Array.isArray(result.transactions));
    test.equal(result.transactions.length, 0);
    test.ok(result.parentHash);
    test.equal(result.parentHash, genesis.hash);
};

Despues de implementar el código que hace pasar a este test, escribí un segundo test algo más completo:

exports['mine block with transaction'] = function (test) {
    var from = utils.hash();
    var to = utils.hash();
    var value = 1000;

    var states = tries.states().put(from, { balance: 3000 });
    var tx = transactions.transfer(from, to, value);
    
    var txs = transactions.txs();
    txs.add(tx);

    var miner = miners.miner(txs);
    
    var genesis = blocks.block();
    
    var result = miner.mine(genesis, states);
    
    test.ok(result);
    test.ok(result.hash);
    test.ok(result.transactions);
    test.ok(Array.isArray(result.transactions));
    test.equal(result.transactions.length, 1);
    
    test.equal(result.transactions[0].from, from);
    test.equal(result.transactions[0].to, to);
    test.equal(result.transactions[0].value, 1000);
    
    test.ok(result.parentHash);
    test.equal(result.parentHash, genesis.hash);
};

Todavía es un test algo débil. Por ejemplo, no obliga a la validación de las transacciones en el proceso de minado, y no está claro todavía que pasa con la transacción que fue incluida en el nuevo bloque. Pero todo esto puede irse agregando en tests, describiendo la conducta esperada, y luego implementando.

La parte interesante de este flujo de trabajo es que la implementación va creciendo, siguiendo el camino más simple, siguiendo lo esperado por los tests.

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted in Bitcoin, Blockchain, Ethereum, JavaScript, NodeJs, Proyectos Open Source | Leave a comment

Resoluciones del Nuevo Mes: Julio 2016

Llegó el dia de escribir mis nuevas resoluciones y repasar las del mes pasado:

– Mejorar WangTiles [pendiente]
– Mejorar WangTilesJS [completo] ver repo
– Mejorar CrysSharp  [completo] ver repo
– Mejorara GoSharp [pendiente]
– Mejorar SimpleForth [completo] ver repo
– Mejorar BlockchainSharp [completo] ver repo
– Mejorar SimpleBlockchain [completo] ver repo

Además, estuve trabajando en:

– Mejorar CrysJS [completo] ver repo

Mis nuevas resoluciones:

– Mejorar WangTiles
– Mejorar WangTilesJS
– Mejorar CrysSharp
– Mejorar CrysJS
– Mejorar SimpleForth
– Mejorar BlockchainSharp
– Mejorar SimpleBlockchain

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted in Blockchain, C#, JavaScript, NodeJs, Proyectos Open Source, Test-Driven Development | Leave a comment

Armando una Blockchain (13)

Anterior Post
Siguiente Post

Una parte importande de una blockchain a la Ethereum, es la ejecución de transacciones de transferencias. Cada cuenta tiene una dirección pública y un estado de cuenta conteniendo su balanca. Los estados de cuenta se almacenan en tries inmutables. Esta semana estuve trabajando en mi proyecto personal de blockchain, escrito en JavaScript/NodeJS:

https://github.com/ajlopez/SimpleBlockchain

para ejecutar una transferencia entre cuentas. Como es habitual, lo codifiqué siguiendo el flujo de trabajo de TDD (Test-Driven Development). Mi primer test:

exports['execute transfer'] = function (test) {
    var from = utils.hash();
    var to = utils.hash();
    var value = 1000;

    var states = tries.states().put(from, { balance: 3000 });

    var tx = transactions.transfer(from, to, value);
    
    test.ok(tx);
    test.equal(tx.from, from);
    test.equal(tx.to, to);
    test.equal(tx.value, value);
    
    var newstates = transactions.execute(tx, states);

    test.ok(newstates);
    
    var oldfromstate = states.get(tx.from);
    
    test.ok(oldfromstate);
    test.equal(oldfromstate.balance, 3000);
    
    var oldtostate = states.get(tx.to);
    
    test.ok(oldtostate);
    test.equal(oldtostate.balance, 0);
    
    var newtostate = newstates.get(tx.to);
    
    test.ok(newtostate);
    test.equal(newtostate.balance, 1000);
    
    var newfromstate = newstates.get(tx.from);
    
    test.ok(newfromstate);
    test.equal(newfromstate.balance, 2000);
}

Luego de la ejecución de una transacción, un nuevo trie de estados de cuenta se arma y se devuelve. Pero también hay que rechazar las transferencias que no tienen fondos:

exports['execute transfer without funds'] = function (test) {
    var from = utils.hash();
    var to = utils.hash();
    var value = 1000;

    var states = tries.states();

    var tx = transactions.transfer(from, to, value);
    
    test.ok(tx);
    test.equal(tx.from, from);
    test.equal(tx.to, to);
    test.equal(tx.value, value);
    
    var newstates = transactions.execute(tx, states);

    test.equal(newstates, null);
    
    var oldfromstate = states.get(tx.from);
    
    test.ok(oldfromstate);
    test.equal(oldfromstate.balance, 0);
    
    var oldtostate = states.get(tx.to);
    
    test.ok(oldtostate);
    test.equal(oldtostate.balance, 0);
}

Para cumplir con esos tests, mi implementación actual, simple, es:

function execute(tx, states) {
    var fromstate = states.get(tx.from);
    var tostate = states.get(tx.to);

    fromstate.balance -= tx.value;
    
    if (fromstate.balance < 0)
        return null;
        
    tostate.balance += tx.value;
    
    return states.put(tx.from, fromstate).put(tx.to, tostate);
}

Próximos posts: ejecutando bloques con transacciones, almacenando permanentemente los tries de estados, smart contracts, etc…

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted in Bitcoin, Blockchain, Ethereum, JavaScript, NodeJs, Proyectos Open Source | Leave a comment

Armando una Blockchain (12)

Anterior Post
Siguiente Post

En un anterior post describí la implementación en C# de un árbol inmutable. Necesito un estructura llamada trie para mantener el estado de las cuentas en la blockchain: sus balances pueden ser recuperados usando la dirección pública de la cuenta. La estructura debería ser inmutable para poder recuperar fácilmente los estados de las cuentas en distintos instantes del tiempo. Cada trie tiene los estados de todas las cuentas en un determinado instante. Al ser inmutable, cuando se agrega un valor, un nuevo trie es creado y el original todavía sigue estando disponible.

En estos dias he agregado una implementación de trie a mi proyecto personal de blockchain escrito en JavaScript/NodeJS:

https://github.com/ajlopez/SimpleBlockchain

La implementación fue escrita usando el flujo de trabajo de TDD (Test-Development Driven). Tengo tests simples como:

exports['put data and get data'] = function (test) {
    var trie = tries.trie();
    
    var result = trie.put('0123', 42).get('0123');
    
    test.ok(result);
    test.equal(result, 42);
};

exports['put two new data and retrieve them'] = function (test) {
    var trie = tries.trie();
    
    var result = trie.put('0123', 42)
        .put('3210', 1);
    
    test.ok(result);
    test.equal(result.get('0123'), 42);
    test.equal(result.get('3210'), 1);
    test.equal(trie.get('0123'), null);
    test.equal(trie.get('3210'), null);
};

Usando un lenguaje dinámico como JavaScript, sin declaración de tipos para las variables y argumentos, pude escribir una implementación muy simple, como una función:

function Trie(values) {
    if (values == null)
        values = [];
        
    this.get = function (key, offset) {
        if (offset == null)
            offset = 0;
            
        var ky = key[offset];
        
        if (offset === key.length - 1)
            return values[ky];
        else if (values[ky])
            return values[ky].get(key, offset + 1);
        else
            return null;
    };
    
    this.put = function (key, data, offset) {
        if (offset == null)
            offset = 0;
        
        var newvalues = values.slice();
        var ky = key[offset];
        
        if (offset === key.length - 1)
            newvalues[ky] = data;
        else {
            if (!newvalues[ky])
                newvalues[ky] = new Trie();
                
            newvalues[ky] = newvalues[ky].put(key, data, offset + 1);
        }
            
        return new Trie(newvalues); 
    };
}

Cada valor tiene una clave (key). Creo un árbol de tries. Para agregar un valor usando una clave, agrego el valor al árbol, usando cada letra en la clave para recorrer el árbol interno del trie. En un lenguaje tipado, debería declarar el tipo de las claves y valores. Pero usando JavaScript, solamente el algoritmo es importante: la declaración de los tipos no es importante para escribir el código.

El argumento offset es usado para seleccionar el caracter de la clave. Así, si la clave tiene cuatro caracteres, el valor es guardado en un trie compuesto de cuatro niveles.

Esta es una implementación simple, que puedo mejorar, escribiendo nuevos tests con la conducta esperada. Algo para agregar: persistencia a disco/archivo/base de datos, y calcular hash por trie. Cada bloque procesado y cada transición tendría un hash con los estados resultados, así puedo recuperar el árbol usando el hash. Y cada bloque tendría el hash del estado esperado al terminar su proceso. Si ese hash del bloque no coincide con el hash del árbol calculado por aplicar las transacciones del bloque, entones no es válido lo que estamos calculando. Todos los nodos de la red está revisando cada bloque que agregan a la blockchain, controlando que los estados resultantes sean los esperados por el que calculó por primera vez un bloque.

Cuando un nuevo bloque es construido, se usa como estado inicial el estado final del bloque padre, se aplica cada transacción a ese estado, y el hash del estado final se guarda con el bloque. De esta forma, todos pueden controlar que cada bloque queda en el mismo estado para todos los nodos de la red, manteniendo la coherencia de los estados de las cuentas, o sea, sus balances.

Próximos posts: proceso de transacciones y bloques, almacenamiento y validación.

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted in Bitcoin, Blockchain, Ethereum, JavaScript, NodeJs | Leave a comment

Compilando y Ejecutando Smart Contracts (1)

Quisiera explorar en esta serie algunas de las opciones para compilar y ejecutar smart contracts en una blockchain. Alguna de estas opciones ya existen, y otras son más experimentales o solamente ideas. Aunque este primer post está centrado en smart contracts con Ethereum, planeo comentar otras implementaciones más adelante.

Si no conocen de smart contracts en Ethereum, recomiendo la lectura de:

A 101 Noob Intro to Programming Smart Contracts on Ethereum
Making Sense of Blockchain Smart Contracts
Writing a contract

El camino usual para programar y ejecutar un smart contra en esta plataforma, es escribir el código fuente en el lenguaje de programación Solidity, compilarlo a bytecodes, y ejecutar el programa resultante usando la Ethereum Virtual Machine:

Pero hay otras opciones en lenguajes de programación, que también compilan a bytecodes Ethereum, como Serpent, LLL:

Pero de lejos, Solidity es el lenguaje de programación más usado. Hay un creciente ecosistema de herramientas alrededor de Solidity, y muchos ejemplos están escritos en este lenguaje.

Otra opción (que yo sepa, aún no implementada), es compilar un lenguaje de programación clásico a bytecodes Ethereum (tal vez imponiendo algunas restricciones):

Esto no es una tarea fácil: el lenguaje de programación original (Java, JavaScript, C#) tiene su propia semántica, que aún con restricciones, podría no ser simple de implementar en bytecodes Ethereum. Pero una ventaja de este camino es que los desarrolladores podrían usar las herramientas (editores, IDEs, depuradores, tests…) original de esos lenguajes para escribir smart contracts.

Ejecutando los bytecodes en una Ethereum Virtual Machine implica leer bytecode por bytecode, y ejecutar su semántica en un gran “switch and loop”. Pero no es ésta la única opción. Los bytecodes podrían ser compilados a algo más optimizado:

Como una implementación de esta forma, hay código en la implementación Ethereum en Go: tienen un compilador JIT (Just In Time), leer el post Optimising the Ethereum Virtual Machine. Fragmento:

The go-ethereum repository implements —among the Ethereum client and tool suite— the Ethereum Protocol in the Go language. It contains two implementation of the EVM, one extremely simple byte code interpreter that simple loops over the byte code and a JIT-like interpreter that compiles the byte code in to manageable data types and structures.

Y todavía hay otro “approach”: compilar la semántica de los bytecodes directamente en un lenguaje de programación clásico, y entonces compilar/interpretar el código resultado usando el compilador/intérprete nativo de ese lenguaje:

El código fuente producido de esta manera podría usar las estructuras de datos de la Ethereum VM, como el almacén (storage) de los contratos. Un tema a resolver en este camino es que los bytecodes producidos pueden haber perdido algo de la intención original del código inicial del contrato (en Solidity, por ejemplo),  porque el compilador original puede haber transformado en formas complicadas la sentencias originales. Como ejemplo, una simple operación de un entero o un string en Solidity se mapea a muchos bytecods, porque no existen esas operaciones simples en la especificación de la Ethereum VM: la VM está orientada a manejar números enteros de 32 bytes (a veces, direcciones de 20 bytes). Entonces, los bytecodes no reflejan en general el código inicial de una forma clara y directa.

Una variante de lo anterior: en vez de generar código fuente en un lenguaje de programación clásico, la salida puede ser directamente bytecodes orientados al ejecutor fina, por ejemplo, bytecodes Java o bytecodes CLR .NET. Pero pienso que esto es sólo un caso de optimización de lo anterior, que primero hay que explorar la generación de código fuente, y recién cuando este camino demuestre alguna ventaja, pasar a generar los bytecodes finales directamente. Generando primero código fuente, sería más fácil investigar la calidad del código generador, depurarlo, mejorarlo. Generar directamente bytecodes finales lo dejaría para una segunda fase.

Otra idea que me gustaría investigar: compilar código fuente existente de un contrato (por ejemplo Solidity) en código fuente de un lenguaje de programación clásico:

De esta manera, la semántica original de enteros, strings, mapas podría ser implementado directamente en Java o en C#: al final, solamente el estado del almacén (storage) es importante en un smart contract Ethereum: es el modo de controlar que todos los nodos ejecutan el contrato de la misma forma. Si un contrato Solidity pudiera ser compilado de esta forma, sin alterar el resultado de su ejecución, es decir, produciendo cada vez que se ejecuta el mismo resultado que cuando es compilado a bytecodes EVM, entonces el programador de contratos podría usar e implantar ese código generado con las herramientas del lenguaje final.

Pienso que Solidity+Ethereum VM es la implementación más popular, en camino a ser el estándar “de facto”, con más y más herramientas en su ecosistema. Pero otras opciones igual merecen una implementación exploratoria.

Próximos posts: otras implementaciones fuera de Ethereum, como la de Lisk que ejecuta smart contracts en JavaScript usando NodeJS; más discusiones de las opciones enumeradas en este post; implementaciones alternativas; investigación de cómo se compila Solidity a bytecodes.

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted in Blockchain, Ethereum, Smart Contracts | Leave a comment

Resoluciones del Nuevo Mes: Junio 2016

Veo de revisar mis resoluciones de mayo:

– Mejorar WangTiles [pendiente]
– Mejorar WangTilesJS [completo] ver repo
– Mejorar CrysSharp [completo] ver repo
– Mejorar BlockchainSharp [completo] ver repo
– Mejorar SimpleBlockchain [completo] ver repo
– Preparar y dar una charla relacionada con Bitcoin [completo]

También estuve trabajando en:

– Mejorar SimpleForth [completo] ver repo

Mis resoluciones para en nuevo mes de junio:

– Mejorar WangTiles
– Mejorar WangTilesJS
– Mejorar CrysSharp
– Mejorar GoSharp 
– Mejorar SimpleForth
– Mejorar BlockchainSharp
– Mejorar SimpleBlockchain

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted in Blockchain, C#, JavaScript, NodeJs, Proyectos Open Source | Leave a comment

Armando una Blockchain (11)

Anterior Post
Siguiente Post

En estos dias estuve refactorizando la implementación de la blockchain de mi proyecto personal en JavaScript/NodeJS:

https://github.com/ajlopez/SimpleBlockchain

En el anterior post había mostrado algunos de los tests que escribí siguiendo el flujo de TDD  (Test-Driven Development). Hoy, quiero mostrar la implementación actual, que es la evolución de la anterior.

La implementación está en:

https://github.com/ajlopez/SimpleBlockchain/blob/master/lib/blockchains.js

Hay ahí una “clase” JavaScript, implementada como función:

function Blockchain(block) {
    var self = this;
    var blocks = [block];
    var blockstore = stores.blockstore();
    blockstore.save(block);
    
    this.bestBlock = function () { return blocks[blocks.length - 1]; }

En mi nueva implementación, estoy usando un almacén de bloques (por ahora en memoria). Este objeto puede registrar/salvar un bloque, recuperar un bloque por hash, recuperar bloques del mismo número de altura. Pero ahora le agregué recuperar bloques que tengan en mismo bloque padre, por hash del bloque padre. De esta forma, puedo recuperar los hijos inmediatos de un bloque. y también sus descendientes. Ahora puedo reconstruir desde ese almacén/store todo el árbol de bloques partiendo de uno inicial.

Vean que el estado de la blockchain tiene una implementación ingenua, sencilla: solo es un arreglo JavaScript, con índice el número de bloque, comenzando con el bloque génesis, que tiene número 0. Mi plan es refactorizar esta implementación para soportar muchos bloques, usando una lista grabada en disco. Pero por ahora, usando esta implementación ingenua, puedo armar la conducta esperada de la aplicación que estoy escribiendo.

Un método que exponso hacia afuera es agregar un bloque:

this.add = function (block) {
    if (blockstore.hasBlockHash(block.hash))
        return;
        
    blockstore.save(block);
    
    if (getUnknownAncestor(block) != null)
        return;
    
    tryAdd(block);
}

Si este bloque es conocido, entonces implica que ya fue procesado, y se sale de la función.

Si no, el bloque es agregado al almacén en memoria, y se calcula el primer ancestro no conocido, pues bien puede que todavía no haya llegado al nodo. Si hay algún ancestro desconocido, no se puede formar todavía una cadena con este bloque, y salimos de la función.

Si el bloque tiene una cadena de ancestros que se termina conectando con el bloque génesis, tratamos de agregarlo a la cadena principal:

function tryAdd(block) {
    if (isBestBlockChild(block))
        blocks.push(block);
    else if (isBetterBestBlock(block))
        tryFork(block);
        
    tryChildren(block);
}

Si es un hijo directo del mejor bloque conocido, lo agregamos a la cadena. Si no, pero es un mejor bloque (por ejemplo, porque tiene una mejor altura que la cadena principal conocida), se intenta armar un fork de la cadena, posiblemente cambiando a otra cadena mejor. En todo caso, se procesan sus hijos inmediatos: tal vez la aparición del bloque permite completar cadenas que estaban pendientes de proceso.

Estos son los predicados que uso:

function isBestBlockChild(block) {
    var bblock = self.bestBlock();
    
    return bblock.hash === block.parentHash && bblock.number === block.number - 1;
}

function isBetterBestBlock(block) {
    var bblock = self.bestBlock();
    
    return bblock.number < block.number;
}

Este es el proceso de los hijos:

function tryChildren(block) {
    var children = blockstore.getChildren(block.hash);

    for (var n in children)
        tryAdd(children[n]);
}

Noten que es una implementación ingenua que implica recursión. Puedo refactorizar el código para no usar recursión.

Dado un bloque, esta función calcula la cadena de ancestros que se une en alguna parte a la cadena principal, y cambia a esa lista como blockchain actual:

function tryFork(block) {
    var newbranch = [block];
    var parentHash = block.parentHash;
    
    while (parentHash && blockstore.hasBlockHash(parentHash)) {
        var parent = blockstore.getByHash(parentHash);
        
        if (parent.hash === blocks[parent.number].hash)
            return switchToFork(newbranch);
            
        newbranch.push(parent);
        
        parentHash = parent.parentHash;
    }
}

Ubicando el ancestro no conocido de un bloque:

function getUnknownAncestor(block) {
    var parentHash = block.parentHash;

    while (parentHash && blockstore.hasBlockHash(parentHash)) {
        var parent = blockstore.getByHash(parentHash);
        
        if (parent.hash === blocks[parent.number].hash)
            return null;
        
        parentHash = parent.parentHash;
    }
    
    return parentHash;
}

Cambiando la cadena actual a una nueva cadena:

function switchToFork(newbranch) {
    for (var n = newbranch.length; n-- > 0😉 {
        var block = newbranch[n];
        blocks[block.number] = block;
    }
}

Todos los tests pasan. Como mencioné, mi plan es ir mejorando la implementación. Pero en mi flujo de trabajo con TDD prefiero ir dando pasos pequeños (“baby steps”), y luego “make it works” para recién ahí pasar a “make it right”, “make it fast”. He tenido buenas experiencias usando este manera de ir escribiendo código, obteniendo implementaciones simples, sólidas, probadas, y fácilmente cambiables y mejorables, donde cada artefacto se agrega ante un caso de uso/test específico, en lugar de armar “arquitecturas de astronauta”.

Animado por este resultado, también refactoricé mi implementación de C#:

https://github.com/ajlopez/BlockchainSharp

Comencé a usar un almacén de bloques que usa GetByParentHash en mi código de BlockChain:

https://github.com/ajlopez/BlockchainSharp/blob/master/Src/BlockchainSharp/Core/BlockChain.cs

Escribí sobre mi anterior implementación en este post.

Nos leemos!

Angel “Java” Lopez

@ajlopez

Posted in Bitcoin, Blockchain, C#, Ethereum, JavaScript, NodeJs, Proyectos Open Source, Test-Driven Development | Leave a comment

Armando una Blockchain (10)

Anterior Post
Siguiente Post

Esta semana pasado, estuve agregando más lógica a mi proyecto personal de blockchain en JavaScript:

https://github.com/ajlopez/SimpleBlockchain

Como es habitual, usando el flujo de trabajo de TDD (Test-Driven Development). Un primer test creando una blockchain con un bloque genesis:

var blockchains = require('../lib/blockchains');
var blocks = require('../lib/blocks');

exports['create blockchain'] = function (test) {
    var genesis = blocks.block();
    var bc = blockchains.blockchain(genesis);
    
    test.ok(bc);
    test.equal(typeof bc, 'object');
    test.equal(bc.bestBlock(), genesis);
};

Luego, un test agregando un bloque:

exports['add block'] = function (test) {
    var genesis = blocks.block();
    var block = blocks.block(genesis);
    var bc = blockchains.blockchain(genesis);
    
    bc.add(block);
    
    test.equal(bc.bestBlock(), block);
};

El rechazo de un bloque que tiene la misma altura que la blockchain actual:

exports['add block same height'] = function (test) {
    var genesis = blocks.block();
    var block = blocks.block(genesis);
    var block2 = blocks.block(genesis);
    
    var bc = blockchains.blockchain(genesis);
    
    bc.add(block);
    bc.add(block2);
    
    test.equal(bc.bestBlock(), block);
};

Agregar un mejor bloque, y luego, el rechazo de un mejor bloque pero que no deciende del mejor bloque actual:

exports['add block with next height'] = function (test) {
    var genesis = blocks.block();
    var block = blocks.block(genesis);
    var block2 = blocks.block(block);
    
    var bc = blockchains.blockchain(genesis);
    
    bc.add(block);
    bc.add(block2);
    
    test.equal(bc.bestBlock(), block2);
};

exports['add block next height but another parent block'] = function (test) {
    var genesis = blocks.block();
    var block = blocks.block(genesis);
    var block2 = blocks.block(genesis);
    var block3 = blocks.block(block2);
    
    var bc = blockchains.blockchain(genesis);
    
    bc.add(block);
    bc.add(block3);
    
    test.equal(bc.bestBlock(), block);
};

Estos tests fueron escritos uno por uno, y cada test fue seguido de la implementación más simple que pudo hacer pasar el test. Esto es parte del espíritu de TDD: pasos de bebé. implementaciones simples, descripción explícita de la conducta esperada.

Próximos posts: implementando estados de cuentas, estados inmutables, comunicación entre nodos.

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Posted in Bitcoin, Blockchain, Ethereum, JavaScript, NodeJs, Proyectos Open Source, Test-Driven Development | Leave a comment