Let’s Create a BlockChain on Nodejs 02

Video Tutorial

Overview

In the last video tutorial, we have covered the basic things about Blockchain on Nodejs how they work and we implemented a very basic blockchain example to actually demonstrate how blocks of transactions gets stored safely on a chain of other endless blocks and this is how today’s Crypto Currencies are based on (Bitcoin, Ethereum…), so we have to take to the next level and make it better therefore in this tutorial we are going to try to redesign some of the features of the application we created the last time alongside that we are going to add a Database support to store the blockchain and all its block with the needed data safely (MongoDB).

To get started you need to have MongoDB installed and have a basic of MongoDB how it works and its workflow, if you don’t you can check out tutorials on MongoDB.

Now you need to install a MongoDB client for Nodejs, we will go with mongoose client.

npm install mongoose chalk --save

We also install chalk which is a module that going to allow us to print colored logs into the console (text color or background) so we can have a helpful log message.

**Here **you can get the Full code Repository.

Re-Setup the Project

the project structure that we were working on isn’t that great with some none-organized code and bit ugly implementation so let’s fix that.

On the src folder add a new file name it validator.js which is responsible for telling if a block is valid and can be added to the blockchain or no.

let hash = require('object-hash');

const TARGET_HASH = 1560;
//Export the function to be used with other module
module.exports.validProof = (proof) => {
    let guessHash = hash(proof);
    console.log("Hashing: ", guessHash);
    return guessHash == hash(TARGET_HASH);
}

module.exports.proofOfWork = () => {
    let proof = 0;
    while (true) {
        if (!module.exports.validProof(proof)) {
            proof++;
        } else {
            break;
        }
    }
    return hash(proof);
}

We simply copied them from the main.js to make it a bit tide.

and you can get rid of everything on the main.js only leave the blockchain instance.

and also create a database/ folder inside the src/ put on it an index.js file that will be the main file for the database connection and model creation.

Mining a New Block

So we were using the addNewBlock function to add for us a new block to the chain instance but this function isn’t responsible for any Block validation or check on the other side we were doing this in the main.js file we check if the block is valid then we call the addNewBlock method to only add, well it works but it’s not the best thing that we can come with therefore we are going to move the validation into the addNewBlock method to do that on its own without hardcoding it.

Here are the steps of mining and adding a block to the chain:

  • Create the Block with the needed data (index, timestamp, ongoing transactions, and prevHash) and also we are going to add the block’s hash as a property so we can use later for double checking that everything is working as expected.

  • Validate the Block using the Nonce (proof) against the desired (TARGET_HASH)

  • The block is valid then Save it on the Database on a MongoDB collection

  • Add it to the instance chain and Clear Ongoing transactions

Simple Enough.

Let’s add the validation of the block on the addNewBlock method.

//change name from proof to TARGET_HASH just to make it simple
const TARGET_HASH = hash(1560);
//require the validator which is an Object that holds the proofOfWork and validProof methods
let validator = require("./validator");

class BlockChain {
...
   AddNewBlock(prevHash) {
     //Construct a New Block
     let block = {
            index: this.chain.length + 1,
            timestamp: Date.now(),
            transactions: this.curr_transactions,
            prevHash: prevHash
        };
        /*Later we need to remove the prevHash method argument and get it from the saved block on 
        the Database*/
        if (validator.proofOfWork() == TARGET_HASH) {
            //Block is Valid and we can add it to the Database 
            //Set current block's Hash (by hashing it)
            block.hash = hash(block);
            //TODO: Next thing is Database Saving
         });
   }

Now it looks much simpler and easier to read through the code then It was earlier, now we need to jump to the most important part which the Database integration to save the new Mined block.

Connect on Database

Open up the index.js file under the database folder we created earlier and let’s make sure to successfully establish a connection to the MongoDB local server.

/* database/index.js */
//Import mongoose MongoDB Client 
let mongoose = require("mongoose");

//Connect to DB
mongoose.connect("mongodb://localhost:27017/blockChain", (err) => {
    if (err)
        return console.log("Cannot connect to DB");
    //Success Message 
    console.log("Database is Connected");
    //Run callback registered onConnect
    connectionCallback();
});
//This is going to run when DB is successfully connected 
let connectionCallback = () => {};
//onConnect is going to be used outside this module to assign the connection callback
module.exports.onConnect = (callback) => {
   //Set custom Callback as the Global Callback to be run when connected to DB
   connectionCallback = callback;
}

Connect to the database that is running by default on localhost port 27017 and we name the database as blockChain also if success we have to run the connectionCallback, this callback is going to be set outside of the index module so we would know when the database has successfully established a connection with us then we can mine and save a block to the chain.

So in the main.js we have first to connect to database then listen for success connection and continue with blocks mining.

/* main.js */
//Make sure to put this first 
let database = require("./src/database");
database.onConnect(() => {
 /*Here where we will do the mining and block creation process once we are successfully connected to 
   the Database so we would face no problems. */
}

What left to us is to save the mined block to the database and before that, we need to create the block MongoDB model schema that we will save the data in to.

Block Model and Save to Database

On the same directory of index.js (database/) create a file name it model.js which going to be responsible for defining the Block Schema and compiling it into a model that we can use it later to store and fetch data from the database (data concerning blockchain).

/* database/model.js */
//Import mongoose 
let mongoose = require("mongoose");
//get Schema Constructor out of mongoose
let Schema = mongoose.Schema;

//Create the BlockChain Schema
let BlockChainSchema = new Schema({
    //block index
    index: {
        required: true,
        type: Schema.Types.Number
    },
    //creation date 
    timestamp: {
        required: true,
        type: Schema.Types.Date,
        default: Date.now()
    },
    //Ongoing transactions 
    transactions: {
        required: true,
        type: Schema.Types.Array
    },
    //prevBlock on the chain hash (not required cause first chain's block has no prevHash)
    prevHash: {
        required: false,
        type: Schema.Types.String
    },
    //Current Block hash (every block should have a unique hash)
    hash: {
        required: true,
        type: Schema.Types.String
    }
});
//Compile & Export Compiled Model after registering it in mongoose model system
module.exports = mongoose.model("BlockChain", BlockChainSchema);

So we are simply creating a new Schema for the blockchain which contains the same properties as a block with it’s specified types and we specifically tell it if it is required or not to make validation process much easier for us when dealing with a lot of a blocks gets mined at the same time.

We set the prevHash required to false cause the chain’s first block has no previous block which means it has the prevHash property set to null.

We have to require the model module for the model to get compiled and register on the mongoose system so we can use it on our block creation system to save it to the database.

/* database/index.js */
//Do it first 
//Import model
let BlockChainModel = require("./model");
...

Now let’s save the block once it’s successfully mined.

/* blockchain.js */
...
addNewBlock(prevHash) {
...
//Create a block instance using the block data we already created
let newBlock = new blockChainModel(block);
newBlock.save((err) => {
    if (err)
        //Error, chalk will help us deliver a nicer red message 
        return console.log(chalk.red("Cannot save Block to DB ", err.message));
    //We use chalk library to display colored text (green for success)
    console.log(chalk.green("Block Saved on the DB"));
});
...
}

From this point, you can just add new transactions and call addNewBlock method to create and save a new Block on the chain & the database.

/* main.js */
//Require blockchain
let BlockChain = require("./src/blockChain");
//Create Instance 
let blockChain = new BlockChain();
//Hash module 
let hash = require('object-hash');
//Add new transactions for the next block that is going to be created 
blockChain.addNewTransaction("islem", "alex", 200);
/*Mine and save new Block (null prevHash) cause we haven't implemented the functionallity to retrieve already saved block's hash from the database and set it as the current block's prevHash*/
blockChain.addNewBlock(null);
//Debugging 
console.log("Chain : ", blockChain.chain);
//Other functionalities are coming on the next tutorial.

You can run this simple using node and see the result.

node ./main.js
...
Hashing:  a87f0fa03c217121dcdaefb986bb5ae18572987b
Hashing:  bac16bcd87ba51195ec8619c3e9612aa5ae3d298
Hashing:  7dcbf5a92ac201dfe417509a6e6fcae2e5edf38a
Hashing:  fb7755092afb7915117e998e08325cf2c3c5b8e6
Hashing:  0e8b0e62e9d9bf1a48cb821b920e8f4738005e47
Hashing:  6ec4364672679c32bd61029feab5cff28b50b2c3
Hashing:  7231a0d44c09bf595dda2749372743d1c367c0c9
Hashing:  fc4afca0e01b81b6320ac18c6518f27278c95e0f
Hashing:  ca027d3d63926b8e5d589bddbd2d424b3d3b0e5a
Hashing:  3703e1eb5e4bff15c9020370db6896d49bf153a3
Chain :  [ { index: 1,
    timestamp: 1537650544780,
    transactions: [ [Object] ],
    prevHash: null,
    hash: 'f6df18260f8898740349cdfeef993968d7965c9c' } ]
Block Saved on the DB

And that is it, we will implement the other features and complete the blockchain in the next tutorial.

What’s Next

So as you can clearly see it is very easy to manipulate a blockchain and add blocks to it also by integrating the support for any database, in this case, we have used the MongoDB Database for storing the mined blocks, and other features like fetching the last block’s hash and set it as current block’s prevHash to get a fully linked blockChain with and optimized proof of work algorithm all will be covered in the next tutorial.

No Comments Yet