DEV Community

Jonathan Thomas
Jonathan Thomas

Posted on • Edited on

My Journey Through Tech:Fullstack Blockchain Course Section 1

As I'm progressing well with my A+ certification course, I believe now is a good get back into coding again. By learning the blockchain development, it'll reinforce what I've learned as I follow along and summarize what I do with each section completed.

First I updated node and npm using nvm. Using nvm I don't have to worry about versions not matching and can actually focus on the project itself.

I also managed to download a stable redis server that for later in the course. I'll be building this in the Ubuntu box.

Next I downloaded the jest library as a dependency and saved it. I confirmed this by checking the package.json file.

I then created the block class using javascript OOP syntax
The constructor arguments include a timestamp, lastHash, hash and data. In an effort to avoid errors such as arguments not being put in order, wrapped the arguments as an object.

So our initial block class looks like this now:

class Block{
constructor({timestamp, lastHash, hash, data}){
this.timestamp = timestamp;
this.lastHash = lastHash;
this.hash = hash;
this.data = data;
}
}

module.exports = Block;

Moving on, we were then to use test driven development methodology by adding the jest script to the package json file watching for errors. We then had to created a test file with the following code:

const Block = require("./block");

describe('Block',() => {
const timestamp = 'a-date';
const lastHash = 'foo-hash';
const hash = 'bar-hash';
const data = ['blockchain', 'data'];
const block = new Block({timestamp,lastHash,hash, data});

it("has a timestamp, lastHash, hash and data property", () => {
    expect(block.timestamp).toEqual(timestamp);
    expect(block.lastHash).toEqual(lastHash);
    expect(block.hash).toEqual(hash);
    expect(block.data).toEqual(data);
});

});

This code states that the block.js file in the same directory will be looked at first to see if it exists. Then using the describe keywork, we set the arguments used in the block constructor from block.js by declaring them as variables in the describe object. The 'it' keyword then uses an anonymous function expecting the arguments of the block class to be found using the toEqual method as a form of testing.

To add more functionality, we created a genesis data that could populate the first block in the chain in a config.js file with the following code:

const GENESIS_DATA = {
timestamp: 1,
lastHash : '-----',
hash :'hash-one',
data: []
};
module.exports = { GENESIS_DATA} ;

Here, we created dummy data that could be used to populate a block. with that in mind we had to require this code in the block.test.js file and the block.js file as such:

const { GENESIS_DATA } = require('./config')

Futher we also had to make sure the instances of the genesis block could be generated during the test by adding the following in the block.test.js file:

describe('genesis()', () => {
//calls instance of genesis blocks this is a static function :)
const genesisBlock = Block.genesis();
console.log('genesisBlock', genesisBlock);

    it('returns a Block instance', () => {
        expect(genesisBlock instanceof Block).toBe(true);
    });

    it('returns the genesis data', () =>{
        expect(genesisBlock).toEqual(GENESIS_DATA);
    });
});

In this describe object, we added we're creating a new instance of a genesis block and checking if it meets the required arguments. Upon testing, an error occurs because we did not define the genesis block as a function inside the block.js file. To remedy and pass the test, we simply add the genesis function to the Clock class like so:

static genesis() {
return new this(GENESIS_DATA);
}

Since we've imported the "{ GENESIS_DATA }" from the config.js file we can now properly create instances of a genesis block.Next within out block.test.js file, we wanted to add the mine Block description like this:

describe('mineBlock()', () =>{
const lastBlock = Block.genesis();
const data = 'mined data';
const minedBlock = Block.mineBlock({ lastBlock, data });

    it('returns a Block instace', () => {
        expect(minedBlock instanceof Block).toBe(true);
    });

    it('sets the `lastHash` to be the `hash` of the lastBlock', () => {
        expect(mineBlock.lastHash).toEqual(lastBlock.hash);
    });

    it('sets the `data`', () => {
        expect(minedBlock.data).toEqual(data);
    });
    it('sets a `timestap`', () => {
        expect(minedBlock.timestamp).not.toEqual(undefined);
    });
});

Here we're testing if the lastHash to be the hash of the previous block, the data of the current block is being mined and the timestamp matches.

Afterwards we added mine block method to the block.js file so that the instances of mineBlock can be generated like so:

static mineBlock({ lastBlock, data }) {
    return new this({
        timestamp: Date.now(),
        lastHash: lastBlock.hash,
        data
    });
}

Now that we've established the block functionality, we need to add hashes to be checked using SHA 256. First we created a crypto-hash.js and crypto-hashe.test.js files respectively:

//crypto-hash.js
const crypto = require('crypto');
const cryptoHash = (...inputs) => {
const hash = crypto.createHash('sha256');

hash.update(inputs.sort().join(' '));

return hash.digest('hex');

};

module.exports = cryptoHash;
In the cyrpto-hash file, we import and require the 'crypto' module of NodeJS. When we declare the cryptoHash, we use the spread operator on the data within the upcoming 'inputs array'. Then we use the update, sort and joint methods to format the hashes from the last block and returns them as a hexadecimal value using the digest built in. This ensures that there will at least be some hasing present regardless of argument orders.

//crypto-hash.test.js

const cryptoHash = require('./crypto-hash');

describe('cryptoHash', () => {

it('generates SHA-256 hashed output', () =>{
    expect(cryptoHash('foo'))   .toEqual('2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae');
});

it('produces the same hash with the same input in any order', () =>{
    expect(cryptoHash('one', 'two','three'))
    .toEqaul(cryptoHash('three','one','two'));
});

});
In the testing file, we got the hash of 'foo' and test to see if it matches up. Furthermore, we now have to update our block/block.test functions respectufully by importing the crypto-hash files from the local directory:
//added to block.js, block.test.js
const cryptoHash = require("./crypto-hash");

Then we updated the mineBlock function to a more completed state like this:
//block.js
static mineBlock({ lastBlock, data }) {

    const timestamp = Date.now();
    const lastHash = lastBlock.hash;

    return new this({
        timestamp,
        lastHash,
        data,
        hash: cryptoHash(timestamp, lastHash, data)
    });
}

Now that we've declared the timestamp,lastHash and data in the cryptoHash module new instances apply a hash to the arguments of the block. We also finalized the mineBlock description test as so:

//block.test.js
describe('mineBlock()', () =>{
const lastBlock = Block.genesis();
const data = 'mined data';
const minedBlock = Block.mineBlock({ lastBlock, data });

    it('returns a Block instace', () => {
        expect(minedBlock instanceof Block).toBe(true);
    });

    it('sets the `lastHash` to be the `hash` of the lastBlock', () => {
        expect(minedBlock.lastHash).toEqual(lastBlock.hash);
    });

    it('sets the `data`', () => {
        expect(minedBlock.data).toEqual(data);
    });
    it('sets a `timestap`', () => {
        expect(minedBlock.timestamp).not.toEqual(undefined);
    });
    it('creates a sha-256 `hash` based on proper inputs', () => {
        expect(minedBlock.hash).toEqual(cryptoHash(minedBlock.timestamp, lastBlock.hash, data));
    });
});

So in summary, I've created a block, started using a test driven development approach, added functionality to the blocks and I'm now ready to move on to the next section.

Personal reflection: This is the most coding I've done in the last 3 months. It feels really good to understand what I'm doing. I've really reinforced object oriented programming concepts in javascript, the use of anonymous functions and was introduced to a new way of developing a project. I fins it also helps that iI actually record what it is I've done after I complete each section. For now I'm off to study the A+ materials for today and will start section 2 of this course in the morning.

Things to keep in mind: There are some portions of javascript I should really become more familiar like spread operators. As such it's probably a good idea to keep up with the documentaion. I should also change my git settings so I can push requests faster, but that's another story.
Anyway that was my the summary of Section 1, constructive criticism is alsways welsom and have a nice day!

Top comments (0)