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

Propuesta de Mejora a la Minería de Blockchain

En estas semanas, lei el post 25-second irreversible confirmations for instant payments de @sdlerner, donde menciona:

Bitcoin forwards a block by packing the block header with all the transactions contained in the block. This strategy, while being the most easy to analyze, is known to perform badly, both regarding block propagation latency and bandwidth usage. Since the transactions on a block are generally already known to the network, there is no benefit in transmitting them again.

Las transacciones incluidas en un bloque podrían ser sustituidas por una lista de hashes. El nodo que recibe la información del nuevo bloque minado podría reconstruir las transacciones a partir de los hashes. Tiene un conjunto interno de transacciones pendientes: de ahi puede traducir los hashes a transacciones. Los hashes que no correspondan a transacciones conocidas deben ser entonces pedidas al otro nodo. Otra alternativa es enviar el encabezamiento del bloque:

…Still another improvement is to forward the block header before even checking the transactions, and only checking the block PoW and height at forward time.Still another improvement is to forward the block header before even checking the transactions, and only checking the block PoW and height at forward time. This allows the header to spread over the network in less than a second. Nodes can then start mining an empty block on top of the header even if the transactions are still missing, during a fixed interval. After that interval, they resume mining in whatever block they were mining before.

(el énfasis es mío) No soy experto en minería ni eficiencia de red, pero puedo proponer una mejora a esta alternativa, al menos en Ethereum, donde existe el concepto de cuenta. En vez de propagar solamente el header, el nodo remoto puede enviar además un predicado de cuentas P(acc) con las siguientes propiedades:

– P(acc) es verdadero para cualquier cuenta involucrada en una transacción del bloque recibido

Una “cuenta involucrada en una transacción” es tanto la cuenta que envía fondos como la que los recibo. Debemos considerar las cuentas que reciben SI SON CONTRATOS, pues pueden cambiar de estado más allá de recibir fondos. En una transacción que sea “solo transferencia de fondos”, debemos considerar involucrada a la cuenta que envía. El punto a entender es: el nodo que recibe la información resumida del nuevo bloque minado NO PUEDE ESTAR seguro del estado de cualquier cuenta involucrada en las transacciones de ese bloque. De las otras cuentas, todas mantienen EL MISMO ESTADO que antes de ese nuevo bloque minado.

Entonces, toda transacción pendiente que tenga cuenta enviadora con P(acc) en falso, y (cuenta receptora sin contrato O con tipo contrato con P(acc) en falso), puede ser incluida en el armado de un nuevo bloque.

La mejora propuesta consiste: en vez de comenzar a minar un bloque vacío, el nodo receptor puede comenzar a minar el bloque usando transacciones pendientes, que cumplan con la condición anterior. Las cuentas que no ven afectado su estado, pueden participar de las transacciones del nuevo bloque.

¿Cómo enviar ese predicado? Una opción es tener un Bloom filter. De nuevo, no conozco mucho de filtros Bloom, pero puedo imaginar una lista de bits. Como ejemplo concreto, usaré 16 bits. Si una cuenta, involucrada en una transacción, tiene una dirección pública que termina en el hexadecimal 0, prendo el primer bit. Si la cuenta involucrada tiene dirección que termina en hexadecimal A, prendo el bit undécimo. De esta manera, puede haber falsos positivos en este filtro, pero cada cuenta involucrada en una transacción del bloque satisface el predicado, y no será incluida en el próximo bloque.

La longitud en bits de este campo podría ser optimizada de acuerdo a la cantidad media de transacciones incluidas por bloque. Si el número de transacciones (o cuentas involucradas) por bloque es alrededor de 16, entonces la longitud de este campo podría ser de 32 bits, como para tener alguna probabilidad de transacciones pendientes con cuentas que no satisfagan el filtro, y puedan ser minadas inmediatamente.

¿Podría esta propuesta ser adaptada para Bitcoin y otros similares? No parece sencillo, al no existir el concepto de cuenta. Habría que usar un filtro de transacciones, pero no siempre podemos saber cuáles de las transacciones pendientes es candidata a minar, porque el nodo no puede ASEGURAR que conozca TODAS las transacciones involucradas: podría haber latencia en la diseminación de las transacciones. Pero supongo que el nodo puede arriesgarse igual a producir un bloque, si la probabilidad de insertar una transacción inválida es baja.

No sé evaluar si esta propuesta puede ser implementada, o si agrega valor, pero me pareción un camino interesante para explorar.

Nota: Desde hace tres meses, soy miembro del equipo de desarrollo de @RSKsmart donde @sdlerner es el Chief Scientific Officer.

Nos leemos!

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

Posted in Bitcoin, Blockchain, Ethereum | Leave a comment