Armando una Blockchain (9)

Anterior Post

Ya estuve publicando detalles de mi proyecto personal de blockchain escrito en C#:

https://github.com/ajlopez/BlockchainSharp

Esta semana comencé otra implementación, esta vez usando JavaScript/NodeJS:

https://github.com/ajlopez/SimpleBlockchain

Es interesante comparar las dos implementaciones, una en un lenguaje tipado y otra en un lenguaje dinámico.

Al igual que en C#, los conceptos bases a implementar son: bloques, transacciones, una blockchain, etc…. Estoy escribiendo el código usando el flujo de trabajo de TDD (Test-Driven Development), como es habitual, para practicar esa disciplina cada dia. La idea es implementar esas entidades de base, y entonces, escribir código de un servidor que pueda comunicarse con otros servidores en una red. Quiero usar mensajes JSON en este proyecto (en C# pienso usar corrientes de bytes sobre sockets). Igual el formato es una decisión que puede cambiar, y sin mayor costo o esfuerzo. Por ahora, necesito implementar la conducta de base, cubierta por los correspondientes tests.

Estos son, por ejemplo, algunos tests de creación de bloques:

exports['create genesis block'] = function (test) {
    var block = blocks.block();
    
    test.ok(block);
    test.equal(typeof block, 'object');
    test.equal(block.number, 0);
    test.ok(isHash(block.hash));
    test.ok(isHash(block.parentHash));
    test.equal(block.parentHash, '0x000....000000');
}

exports['create child block'] = function (test) {
    var genesis = blocks.block();
    var block = blocks.block(genesis);
    
    test.ok(block);
    test.equal(typeof block, 'object');
    test.equal(block.number, 1);
    test.ok(isHash(block.hash));
    test.ok(isHash(block.parentHash));
    test.equal(block.parentHash, genesis.hash);
}

exports['create child block with initial data'] = function (test) {
    var genesis = blocks.block();
    var block = blocks.block({ extra: 'hello' }, genesis);
    
    test.ok(block);
    test.equal(typeof block, 'object');
    test.equal(block.number, 1);
    test.ok(isHash(block.hash));
    test.ok(isHash(block.parentHash));
    test.equal(block.parentHash, genesis.hash);
    test.equal(block.extra, 'hello');
}

Escribo esos tests, uno por uno, y luego de cada test, escribo el código de producción más simple que hace que el test pase. De esa manera, voy avanzando siempre sobre una solución simple a la conducta esperada. Y si luego se me ocurre una mejor implementación, puedo refactorizar y hasta rediseñar, sabiendo que la conducta no cambia ejecutando los tests. Tanto la simplicidad obtenida como la facilidad para el cambio me parecen grandes aportes de seguir este flujo de trabajo.

Despues de las entidades de base, necesito algunas entidades auxiliares, especialmente para permitir el proceso eficiente de bloques y transacciones. Una de esas entidades ayudantes es un almacén de bloques: un lugar donde guardar y recuperar bloques, por hash, hash padre, número. Siguiendo el principio de simplicidad, por ahora tengo una implementación en memoria, vean algunos tests:

exports['create store'] = function (test) {
    var store = stores.blockstore();
    
    test.ok(store);
    test.equal(typeof store, 'object');
};

exports['retrieve unknown block by hash'] = function (test) {
    var store = stores.blockstore();
    
    var block = store.getByHash(utils.hash());
    
    test.equal(block, null);
};

exports['save block and retrieve it by hash'] = function (test) {
    var store = stores.blockstore();
    var hash = utils.hash();
    var block = { hash: hash };
    
    store.save(block);
    
    var result = store.getByHash(hash);
    
    test.ok(result);
    test.equal(result.hash, hash);
};

Voy a seguir trabajando en ambos proyectos: el de C# necesita mejorar el proceso de bloques, y algo de implementación de servidor de red. Con el de JavaScript posiblemente llegue primero a implementar nodos corriendo en red, sin transacciones, bloques vacios intercambiándose entre pares, formando una blockchain por consenso. Algo lindo de la implementación de JavaScript es que no tengo que preocuparme por la concurrencia de varios threads. Puedo, por ejemplo, cambiar la estructura de la blockchain sin preocuparme que otros threads esten ingresando al mismo tiempo a consultarla o actualizarla.

Nos leemos!

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

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

Armando una Blockchain (8)

Anterior Post
Siguiente Post

En el anterior post, describí parte de la virtual machine que estoy incorporando a mi proyecto personal de blockchain, escrito en C#, usando el flujo de trabajo de TDD:

https://github.com/ajlopez/SimpleBlockchain

Agregué un simple compilador de bytecodes, para simplificar algunos tests. Esta clase no es necesaria en producción, pero aún así quedó en el proyecto core:

public class BytecodeCompiler
{
    private IList<byte> bytes = new List<byte>();

    public void Stop()
    {
        this.Compile(Bytecodes.Stop);
    }

    public void Add()
    {
        this.Compile(Bytecodes.Add);
    }

    public void Subtract()
    {
        this.Compile(Bytecodes.Subtract);
    }
    
    // more methods
    
    public byte[] ToBytes()
    {
        return this.bytes.ToArray();
    }
}

Lo que hace es coleccionar una serie de bytecodes, con argumentos opcionales. Y tiene un método que devuelve esa serie como un arreglo de bytes. Un simple test mostrando su uso:

[TestMethod]
public void LessThan()
{
    BytecodeCompiler compiler = new BytecodeCompiler();

    compiler.Push(2);
    compiler.Push(2);
    compiler.LessThan();
    compiler.Push(0);
    compiler.Push(1);
    compiler.LessThan();
    compiler.Push(1);
    compiler.Push(0);
    compiler.LessThan();

    Machine machine = new Machine();

    machine.Execute(compiler.ToBytes());

    var stack = machine.Stack;

    Assert.IsNotNull(stack);
    Assert.AreEqual(3, stack.Size);
    Assert.AreEqual(DataWord.Zero, stack.ElementAt(2));
    Assert.AreEqual(DataWord.Zero, stack.ElementAt(1));
    Assert.AreEqual(DataWord.One, stack.ElementAt(0));
}

También escribí un simple compilador de líneas, llamado SimpleCompiler. Lo puedo usar así en mis tests:

[TestMethod]
public void IsZeroUsingSimpleCompiler()
{
    string program = "push 2\n" +
        "iszero\n" +
        "push 0\n" +
        "iszero";

    SimpleCompiler compiler = new SimpleCompiler(program);

    Machine machine = new Machine();

    machine.Execute(compiler.Compile());

    var stack = machine.Stack;

    Assert.IsNotNull(stack);
    Assert.AreEqual(2, stack.Size);
    Assert.AreEqual(DataWord.Zero, stack.ElementAt(1));
    Assert.AreEqual(DataWord.One, stack.ElementAt(0));
}

Estas son clases auxiliares, pero me simplificaron la escritura de algunos tests. Es parte de mi estrategia, el que la escritura de tests sea facilitada con el tiempo. Al principio escribo tests que involucran mayor trabajo, pero luego, en algún momento, ya apoyado en esos tests de base, los próximos se pueden escribir con más confianza usando estas clases auxiliares.

En el próximo post, una sorpresa: nuevo proyecto de blockchain, pero esta vez en mi querido NodeJS y JavaScript.

Nos leemos!

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

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

Resoluciones del Nuevo Mes: Mayo 2016

Tiempo de escribir las resoluciones del nuevo mes, y repasar las de abril:

– Mejorar WangTiles [completo] ver repo
– Mejorar BlockchainSharp [completo] ver repo
– Comenzar Blockchain in JavaScript [completo] ver repo
– Trabajar on EthSharp [pendiente]
– Trabajar SimpleGA [pendiente]
– Mejorar AjGenesisNode-Express [pendiente]
– Trabajar en CrysJS [pendiente]
– Trabajar en CrysSharp [pendiente]

Adicionalmente, estuve trabajando en:

– Meorar SimpleForth [completo] ver repo
– Comenzar WangTilesJS [completo] ver repo

Mis resoluciones del nuevo mes son:

– Mejorar WangTiles
– Mejorar WangTilesJS
– Mejorar CrysSharp
– Mejorar BlockchainSharp
– Mejorar SimpleBlockchain
– Preparar y dar una charla relacionada con Bitcoin

Nos leemos!

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

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

Armando una Blockchain (7)

Anterior Post
Siguiente Post

En mi proyecto personal de blockchain:

https://github.com/ajlopez/BlockchainSharp

quiero tener la capacidad de ejecutar código, lo que se llama codechain, o smart contracts. He adoptado las ideas de la máquina virtual de Ethereum (ver el Yellow Paper de Ethereum). Algunas clases:

Un DataWord representa un número usando 32 bytes. He implementado la aritmética de esos números usando internamente como base a System.Numerics.BigInteger. Puedo crear DataWord desde enteros y arreglos de bytes.

El Stack es una pila de DataWords, manipulada por la máquina virtual en Machine. Hay una enumeración de los bytecodes implementados, llamada justamente Bytecodes, que se ejecutan en la Machine. Un programa consiste en una serie de bytecodes, contenidos en un arreglo de butes. El método Machine.Execute es donde esos bytecodes son recorridos y ejecutados, modificando una pila, y próximamente, el Storage del contrato, y la Memory asociada en el momento de ejecución. Fragmento del código:

public void Execute(byte[] bytecodes)
{
    int pc = 0;
    int pl = bytecodes.Length;

    while (pc < pl)
    {
        byte bytecode = bytecodes[pc++];

        switch (bytecode)
        {
            case (byte)Bytecodes.Stop:
                return;
            case (byte)Bytecodes.Add:
                this.stack.Push(this.stack.Pop().Add(this.stack.Pop()));
                break;
            case (byte)Bytecodes.Multiply:
                this.stack.Push(this.stack.Pop().Multiply(this.stack.Pop()));
                break;
            case (byte)Bytecodes.Subtract:
                this.stack.Push(this.stack.Pop().Subtract(this.stack.Pop()));
                break;
                
            // more operations
        }
    }
}

El Storage estará asociada a la cuenta del contrato en ejecución. Cada contrato es una cuenta, como otras, con una dirección, balance, código inmutable, y almacenamiento. La Memory es transitoria, y solo se aloca para la ejecución de un contrato, y no persiste más allá de la ejecución. En cambio, el Storage sí vive más allá de cada ejecución, y es parte del estado del mundo que cada nodo de la red debe mantener por cuenta..

Tengo también un simple compilador de bytecodes, y un compilado de comandos por línea, para facilitar la creación de programas, y todo escrito usando el flujo de trabajo de TDD (Test-Driven Development).

Próximos posts: descripción del Storage, Memory, compiladores, ejecución de bloques y transacciones, y almacenamiento persistente.

Nos leemos!

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

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

Armando una Blockchain (6)

Anterior Post
Siguiente Post

Esta semana pasada, agregué proceso de transacciones a mi proyecto personal de blockchain:

https://github.com/ajlopez/BlockchainSharp

En el anterior post, describí el Trie inmutable que estuve armando. Ahora voy a usarlo para guardar el AccountState por dirección de cuenta:

public class AccountState
{
    private BigInteger balance;

    public AccountState(BigInteger balance)
    {
        if (BigInteger.Compare(BigInteger.Zero, balance) > 0)
            throw new InvalidOperationException("Invalid balance");

        this.balance = balance;
    }

    public BigInteger Balance { get { return this.balance; } }

    public AccountState AddToBalance(BigInteger amount)
    {
        return new AccountState(BigInteger.Add(this.balance, amount));
    }

    public AccountState SubtractFromBalance(BigInteger amount)
    {
        return new AccountState(BigInteger.Subtract(this.balance, amount));
    }
}

Decidí implementar cuentas como en Ethereum: tener una cuenta con saldo en luegar de inputs y outputs. Por ahora, la única propiedad es el Balance, pero iré agregando más datos.  Vean arriba que los saldos negativos son rechazadas. He agregado un  TransactionProcessor:

public class TransactionProcessor
{
    private Trie<AccountState> states;

    public TransactionProcessor(Trie<AccountState> states)
    {
        this.states = states;
    }

    public Trie<AccountState> States { get { return this.states; } }

    public bool ExecuteTransaction(Transaction transaction)
    {
        var states = this.states;

        try
        {
            foreach (var av in transaction.Inputs)
            {
                var addr = av.Address.ToString();
                var state = states.Get(addr);
                var newstate = state.SubtractFromBalance(av.Value);
                states = states.Put(addr, newstate);
            }

            foreach (var av in transaction.Outputs)
            {
                var addr = av.Address.ToString();
                var state = states.Get(addr);
                var newstate = state.AddToBalance(av.Value);
                states = states.Put(addr, newstate);
            }

            this.states = states;

            return true;
        }
        catch (Exception ex)
        {
            return false;
        }
    }
}

Que parte de un estado de cuentas y va construyedo otro. Si la transacción es procesado, un nuevo trie es generado, y ExecuteTransaction retorna true. Si la transacción es rechazada (la causa podría ser que al aplicarla resulte un saldo negativo), el trie inicial se mantiene. Un test típico que escribí:

[TestMethod]
public void ExecuteTransaction()
{
    var transaction = CreateTransaction(100);

    var addr1 = transaction.Inputs.First().Address;
    var addr2 = transaction.Outputs.First().Address;

    var states = new Trie<AccountState>(new AccountState(BigInteger.Zero));

    states = states.Put(addr1.ToString(), new AccountState(new BigInteger(200)));

    var processor = new TransactionProcessor(states);

    Assert.IsTrue(processor.ExecuteTransaction(transaction));

    var newstates = processor.States;

    Assert.IsNotNull(newstates);
    Assert.AreNotSame(states, newstates);

    Assert.AreEqual(new BigInteger(200), states.Get(addr1.ToString()).Balance);
    Assert.AreEqual(BigInteger.Zero, states.Get(addr2.ToString()).Balance);

    Assert.AreEqual(new BigInteger(100), newstates.Get(addr1.ToString()).Balance);
    Assert.AreEqual(new BigInteger(100), newstates.Get(addr2.ToString()).Balance);
}

El método auxiliar CreateTransaction crea una transacción con un monton, y dos direcciones creadas al azar.

Estoy pensando en tener solamente una cuenta sender y una cuenta receiver por transacción, como en Ethereum. De hecho, ya ayer lo reimplementé así, haciendo rediseño y refactor, ayudado por toda la batería de tests que ya me daba TDD. El cambio fue fácil y apenas tomó unos minutos.

Próximos temas: ejecutar bloques con transacciones, guardar el estado resultante en un almacén persistente, implementación de la máquina virtual y su ejecución de bytecodes, el compilador simple que armé, etc…

Nos leemos!

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

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

Armando una Blockchain (5)

Anterior Post
Siguiente Post

En esta semana pasada estuve trabajando bastante en mi proyecto personal:

https://github.com/ajlopez/BlockchainSharp

implementando una blockchain en C#, usando como es habitual el flujo de trabajo de TDD (Test-Driven Development). Un elemento que necesito implementar es el almacenamiento (store) de los estados de cuentas (en principio, voy a guardar sus balances). El balance de una cuenta debe poder ser recuperado por el id de la cuenta (un hash). Pero en muchos casos de uso, necesito conocer los balances de algunas cuentas a UN INSTANTE dado de tiempo. No es suficiente tener los balances de las cuentas al tiempo actual, solamente. Para cumplir con esos casos de uso, implementé un trie pero inmutable.

Un trie es un árbol donde los nodos no terminales almacenan parte de la clave:

En el ejemplo de la figura de arriba, el valor V1 está asociado con la clave AAA, y el valor V5 está asociado con la clave ACA. CUando cambio el valor asociado con la clave ABC desde V4 a V7, entonces, un nuevo trie es creado, manteniéndose el anterior sin modificarlo:

Puedo acceder el par original clave/valor usando a partir de la “vieja raíz” del trie, y cuando necesito valores más actuales, cambio a usar la “nueva raíz” del nuevo trie. Si algún nodo o porción del árbol queda inalcanzable, el recolector de basura liberará la memoria asociada.

La implementación del trie que tengo ahora es simple, y está basada en haber escrito los test e implementado el código que hace que los test pases. Un ejemplo de test:

[TestMethod]
public void PutAndGetKeyValue()
{
    Trie<string> trie = new Trie<string>();

    var trie2 = trie.Put("012", "foo");

    Assert.IsNotNull(trie2);
    Assert.AreNotSame(trie2, trie);
    Assert.IsNull(trie.Get("012"));
    Assert.AreEqual("foo", trie2.Get("012"));
}

Otro ejemplo que muestra que los tries mantienen sus valores, aún cuando se crean nuevos tries en cada actualización:

[TestMethod]
public void ReplaceValue()
{
    Trie<string> trie = new Trie<string>();

    var trie2 = trie.Put("012", "foo");
    var trie3 = trie2.Put("012", "bar");

    Assert.IsNotNull(trie2);
    Assert.AreNotSame(trie2, trie);
    Assert.IsNull(trie.Get("012"));
    Assert.AreEqual("foo", trie2.Get("012"));

    Assert.IsNotNull(trie3);
    Assert.AreNotSame(trie3, trie2);
    Assert.AreEqual("bar", trie3.Get("012"));
}

Mi idea es usar Trie<AccountState> como un almacén de los estados de cuenta. Al final del proceso de cada bloque y de cada transacción, habrá un trie de estado de cuentas. Y al final del siguiente bloque, habrá otro trie, con los balances actualizados. En cualquier momento, puedo recuperar los estados de las cuentas al final de bloque 1, o al final del bloque 2, partiendo de los respectivos tries.

Nos leemos!

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

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

Armando una Blockchain (4)

Anterior Post
Siguiente Post

En este post quiero describir algunas de las partes esenciales a implementar en el ejemplo de blockchain que estoy escribiendo en:

https://github.com/ajlopez/BlockchainSharp

usando C# y TDD (Test-Driven Development). Lo principal a implementar son:

– Bloques
– Transacciones

y los conceptos de:

– Cuenta
– Estado de Cuenta
– Smart Contracts (ejecutados en una máquina virtual)

He decidido usar Cuenta y Saldo, a la Ethereum, en vez de usar los UTXO (Unspent Transactions Output) de Bitcoin. Ver un buen post sobre la diferencia en Thoughts on UTXOs by Vitalik Buterin, Co-Founder of Ethereum.

Además, necesito utilitarios para:

– Codificar/Decodificar entidades a ser transmitidas/recibidas entre los nodos (he decidido usar arreglos de bytes para transmitir, bien podría, en otra implementación, por ejemplo, JavaScript pero aún en ésta de C#, usar simples JSONs).
– Calcular Hashes
– Implementar Tries immutables (algo hay ya de código en el proyecto)
– Firmar transacciones y verificar la firma
– Verificar la integridad del bloque
– Verificar que las transacciones son válidas (p.ej. que las cuentas que envían valores tienen saldo suficiente)
– Cálculo de Proof of Work en los mineros, como es usual en las implementaciones de Bitcoin y Ethereum.
– Almacenar algunas entidades: bloques completos, bloques parciales (Ethereum usa Block Header), estado de cuenta (saldo…), en general usar tries inmutables con algún soporte fuera de memoria.

Hace unos días, comencé a escribir una clase Transaction, que tiene cuentas y valores. Cada cuenta es identificada por una dirección (actualmente un string hexadecimal aleatorio):

Cada transacción tiene uno o más entradas y salidas. Cada entrada/salida es una dirección y un valor. Los valores son instancias de System.Numerics.BigInteger, así puedo manejar grandes cantidades de unidades pequeñas. En el mundo de las criptomonedas es usual el uso de valores enteros que expresan fracciones mínimas..

Próximos pasos: agregar transacciones a los bloques, aplicar transacciones a los estados de cuenta, validar que los valores estén disponibles, almacenar los estados resultantes en tries, etc,…

Nos leemos!

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

Posted in Bitcoin, Blockchain, C#, Ethereum, Proyectos Open Source | Leave a comment

Resoluciones del Nuevo Mes: Abril 2016

Un nuevo mes comienza, ya vamos adentrándonos en el año, y es tiempo de escribir las nuevas resoluciones mensuales. Y tiempo de revisar las del mes pasado:

– Mejorar AjGenesisNode-Express [pendiente]
– Trabajar en CrysJS [completo] ver repo
– Trabajar en CrysSharp [pendiente]
– Mejorar mis ejemplos de SimpleGA [pendiente
– Trabajar en SharpGo [pendiente]
– Trabajar en EthSharp [completo] ver repo

También trabajé en:

– Mejorar SimpleForth en JavaScript [completo] ver repo
– Comenzar WangTiles en C# [completo] ver repo
– Publicar una nueva versión de SimpleArgs [completo] ver repo
– Comenzar BlockchainSharp en C# [completo] ver repo
– Mejorar los ejemplos de SimpleDT [completo] ver repo
– Mover AjGo a GitHub [completo] ver repo
– Mejorar RuScript [completo] ver repo
– Agregar Code Coverate a ethereumjs rlp [complete] ver repo
– Dar una nueva charla sobre Machine Learning en JavaScript [completo] ver repo ver charla

Mis nuevas resoluciones:

– Mejorar WangTiles
– Mejorar BlockchainSharp
– Comenzar Blockchain en JavaScript
– Trabajar en EthSharp
– Mejorar SimpleGA
– Mejorar AjGenesisNode-Express
– Trabajar on CrysJS
– Trabajar en CrysSharp

Nos leemos!

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

Posted in Uncategorized | Leave a comment

Armando una Blockchain (3)

Anterior post
Siguiente post

Agregué bastante código en estos días a mi simple implementación de una blockchain, escrita en C#:

https://github.com/ajlopez/BlockchainSharp

Como es usual, seguí el flujo de trabajo de TDD (Test-Driven Development), persiguiendo también la simplicidad en cada paso, haciendo baby steps, avanzando de a poco pero firme. En el anterior post mencioné el uso de un DSL (Domain Specific Language) para especificar algunos procesos de bloques que tienen un preparado (setup) largo.

Inicialmente, escribí test como:

[TestMethod]
public void ProcessTwoBlocksAndTwoUncles()
{
    Block genesis = new Block(0, null);
    Block block = new Block(1, genesis.Hash);
    Block uncle1 = new Block(1, genesis.Hash);
    Block uncle2 = new Block(2, uncle1.Hash);

    BlockProcessor processor = new BlockProcessor();

    processor.Process(genesis);
    processor.Process(block);
    processor.Process(uncle1);
    processor.Process(uncle2);

    Assert.IsNotNull(processor.BlockChain);
    Assert.AreEqual(2, processor.BlockChain.BestBlockNumber);
    Assert.AreEqual(genesis, processor.BlockChain.GetBlock(0));
    Assert.AreEqual(uncle1, processor.BlockChain.GetBlock(1));
    Assert.AreEqual(uncle2, processor.BlockChain.GetBlock(2));
}

La idea es:

– Crear algunos bloques
– Enviar los bloques al procesador de bloques
– Revisar los bloques que entonces quedaron en la blockchain

Los bloques creados están vinculados por relaciones de padre-hijo. Algunas veces, un bloque competitivo es creado, y el procesador de bloques debe manejar la existencia de ramas alternativas, que compiten por llegar a ser la nueva blockchain.

El preparado, setup del código puede ser largo. Así que en unos minutos pude escribir un DSL que me permite escribir tests como:

[TestMethod]
public void SendTwoBlocksAndTwoUncles()
{
    var processor = new BlockProcessor();
    var dsl = new BlockProcessorDsl(processor);

    dsl.Run(new string[] 
    {
        "chain g0 b1 b2",
        "chain b1 c2 c3",
        "send b1 b2",
        "send c2 c3",
        "top c3"
    });
}

Cada comando del DSL es un texto, con verbo y argumentos. El bloque g0 es el bloque génesis. El verbo “chain” enumera una lista de bloques a ser creados, cada uno es bloque hijo del anterior. El verbo “send” envía los bloques creados en memoria al procesador de bloques. El verbo “top” verifica que el bloque especificado sea el mejor de la blockchain actual.

El resultado no debe depender del orden de llegada de los bloques, por ejemplo:

[TestMethod]
public void SendTwoBlocksInReversedOrder()
{
    var processor = new BlockProcessor();
    var dsl = new BlockProcessorDsl(processor);

    dsl.Run(new string[] 
    {
        "chain g0 b1 b2",
        "send b2 b1",
        "top b2"
    });
}

Podría agregar texto en archivos, cada uno representado un test, y ejecutarlos todos desde código. Por ahora, sigo con estos tests explícitos en código.

En los próximos posts: las implementaciones esenciales del problema (bloque, transacción, estado…) que son necesarios para armar  una block chain, serialización (a bytes), e implementaciones como tries inmutables para almacenar los estados mutables.

Nos leemos!

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

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

Armando una Blockchain (2)

Anterior Post
Siguiente Post

En los días pasados, escribí una primera implementación de una blockchain, usando TDD (Test-Driven Development). Las decisiones que tomé fueron guiadas por la simplicidad: la blockchain reside en memoria, y los bloques se identifican por un número y un hash. Dos bloques que tengan el número 42 son diferentes si tienen diferentes hashes. Un bloque contiene también el hash del bloque padre (el número del padre no hace falta tenerlo, es el número del bloque hijo menos uno). El bloque génesis (el primer bloque) tiene número 0, y como hash padre tiene null. De esta manera simple, tengo todos los ingredientes para ir armando una blockchain, desde el bloque génesis en adelante, encadenando los bloques usando sus números y hashes.

Tengo una clase BlockChain (sí, prefiero usar mayúscula en la c). Hay un método para agregar un bloque, que puede devolver verdadero o falso. Sólo admite el bloque si su padre es el último bloque de la blockchain, controlando tanto número como hash esperado.

Pero existen otros nodos activos que envían otros bloques, que pueden ser agregados o no a la blockchain. ¿Cómo procesar esos bloques? Los bloques que no puedo agregar en la blockchain los agrego en otras cadenas alternativas, que llamé blockbranch:

En la segunda blockbranch de la figura, el bloque padre de su bloque 41 es todavía desconocido. Pero si llega ese bloque está todo listo para agregarlo al principio de la blockbranch. La primera blockbranch de la figura está ya conectada con la blockchain principal, compartiendo el bloque 40. Esa blockbranch no es blockchain porque tiene menos bloques que la principal. Ese es el algoritmo que elegí para decidir cuál es la blockchain: la cadena más larga obtenida, que comience desde el génesis.

Una blockbranch tienen uno o más bloques consecutivos. Esos bloques no forman parte de la blockchain actual. Pero una blockbranch puede unirse a un bloque de la blockchain o también de otra blockbranh, formando un árbol incipiente. Cada blockbranch es una proto-blockchain.

Cuando tengo suficientes bloques en una blockbranch, llegando a conectarse a otra que llegue hasta el bloque génesis, entonces esa rama es candidata a ser una blockchain. Supongamos que un nuevo bloque arriva al sistema:

El nuevo bloque es el padre del bloque 41 de la segunda blockbranch. Y resulta que su padre, un bloque 39, también es un bloque conocido, esta vez está en la blockchain principal. Entonces ahora, la segunda blockbranch ha llegado a completar una cadena de bloques desde el bloque génesis, hasta un bloque 43.

Si la rama de bloques es válida (si al aplicar los bloques al estado del final del bloque 39, se obtienen nuevos estados válidos, por ejemplo, si fuera una blockchain de criptomonedas: que en los nuevos bloques no hubiera transferencias inválidas), entonces la rama de bloques es válida. Si además, es más alta (tiene más bloques) que la blockchain principal, entonces la desplaza, y es promovida a ser blockchain, quedando:

El proceso de agregar bloques de esta manera, funciona aunque los bloques lleguen en orden diferente. Para manejar el crecimiento de la blockchain, y el formado y vigilancia de las blockbranches, y su promoción a mejor blockchain, tengo un objeto separado que llamé BlockProcessor, a cargo de toda esta orquestación. El procesador recibe nuevos bloques, y de a uno los va agregando a la blockchain, a una blockbranch, o a veces los rechaza (por ejemplo, cuando viene un bloque repetido que ya haya procesado; esto puede pasar, en el sistema final los bloques vienen de la red, y un mismo bloque puede ser enviado a nosotros desde distintos nodos). Puede detectar conexiones entre ramas y la cadena principal, y puede detectar la promoción de ramas a cadenas completas.

En el próximo post: detalles de un DSL (Domain Specific Language) que armé para diferentes escenarios de un block processor.

Nos leemos!

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

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