What problem will you solve implementing this private Blockchain application?

Your employer is trying to make a proof of concept on how a Blockchain application can be implemented in his company.

He is an astronomy fan and because of that he spends most of his free time searching stars in the sky, that’s why he wants to create a test application that allows him and his friends to register stars, and track the ownership of each.

it was a difficult project for me as I don’t know much about node.js, javascript and REST APIs but somehow I made it work.

First part of the project is about filling the code where requested, so basically develop a few functionalities that were lacking. I will not get into the details of the implementation. The full code can be found on my github : github link

  • We downloaded the boilerplate code
  • Installed the required libraries with npm install
  • run the current application using node app.js
  • Check in your terminal the the Express application is listening on PORT 8000

First task is to implement the validate() method in the block class that will validate that the block has not been tampered with by veryfing the hash.

    /**
     *  validate() method will validate if the block has been tampered or not.
     *  Been tampered means that someone from outside the application tried to change
     *  values in the block data as a consecuence the hash of the block should be different.
     *  Steps:
     *  1. Return a new promise to allow the method be called asynchronous.
     *  2. Save the in auxiliary variable the current hash of the block (`this` represent the block object)
     *  3. Recalculate the hash of the entire block (Use SHA256 from crypto-js library)
     *  4. Compare if the auxiliary hash value is different from the calculated one.
     *  5. Resolve true or false depending if it is valid or not.
     *  Note: to access the class values inside a Promise code you need to create an auxiliary value `let self = this;`
     */
     validate() {
        let self = this;
        return new Promise((resolve, reject) => {
          try {
            // Save in auxiliary variable the current block hash
            const currentHash = self.hash;
            self.hash = null;
            // Recalculate the hash of the Block
            const newHash = SHA256(JSON.stringify(self)).toString();
            self.hash = currentHash;
            // Comparing if the hashes changed and return true or false
            resolve(currentHash === newHash);
          } catch (err) {
            reject(new Error(err)); 
          }
        });
      }

Second step is to implement the getBData() that will return the data stored in the body of the block and decode it :

    /**
     *  Auxiliary Method to return the block body (decoding the data)
     *  Steps:
     *  
     *  1. Use hex2ascii module to decode the data
     *  2. Because data is a javascript object use JSON.parse(string) to get the Javascript Object
     *  3. Resolve with the data and make sure that you don't need to return the data for the `genesis block` 
     *     or Reject with an error.
     */
    getBData() {
        let self=this;

        return new Promise( async (resolve, reject) => {          
            let enc_data = this.body;       // Getting the encoded data saved in the Block                                    
            let dec_data = hex2ascii(enc_data); // Decoding the data to retrieve the JSON representation of the object
            let decdata_in_JSON=JSON.parse(dec_data); // Parse the data to an object to be retrieve.
            // Resolve with the data if the object isn't the Genesis block
            if (this.height == 0) {
                //This is the genesis block as height == 0
                resolve("This is the Genesis block dude");
            } else {
                resolve(decdata_in_JSON);
            }
        });

    }

Third step is to implement the _addblock(block) method that will ad block in the chain :

/**
     * _addBlock(block) will store a block in the chain
     * @param {*} block 
     * The method will return a Promise that will resolve with the block added
     * or reject if an error happen during the execution.
     * You will need to check for the height to assign the `previousBlockHash`,
     * assign the `timestamp` and the correct `height`...At the end you need to 
     * create the `block hash` and push the block into the chain array. Don't for get 
     * to update the `this.height`
     * Note: the symbol `_` in the method name indicates in the javascript convention 
     * that this method is a private method. 
     */
     _addBlock(block) {
        let self = this;
        return new Promise(async (resolve, reject) => {
            block.height = self.chain.length; //get current height
            block.time = new Date().getTime().toString().slice(0,-3); //get current time
            if(self.chain.length>0){
                block.previousBlockHash = self.chain[self.chain.length-1].hash; //get previous hash
            }
            block.hash = SHA256(JSON.stringify(block)).toString(); //calculate hash
            //Validation
            console.debug('validation of chain starts here');
            let errors = await self.validateChain(); //call the validate chain method
            console.log(errors)
            console.debug('Validation of chain ended')
            if (errors.length === 0 ){ //if no errors in blockchain
                self.chain.push(block); //push new block
                self.height++; //increment height
                resolve(block) //resolve the new block
            }else{
                reject(errors);
            }
        });

When you first implement this method you are not asked to do the validation but at some point you will be asked to implement the validateChain() method and then you will have to also validate the chain, I included the code directly here

You will then be asked to implement the requestMessageOwnershipVerification() that will allow you to request a message that you will use to sign it with your bitcoin wallet. I did not use bitcoin core or electrum, I used this lightweight solution : https://reinproject.org/bitcoin-signature-tool/#sign. Worked liked a charm.

    /**
     * The requestMessageOwnershipVerification(address) method
     * will allow you  to request a message that you will use to
     * sign it with your Bitcoin Wallet (Electrum or Bitcoin Core)
     * This is the first step before submit your Block.
     * The method return a Promise that will resolve with the message to be signed
     * @param {*} address 
     */
    requestMessageOwnershipVerification(address) {
        return new Promise((resolve) => {
            const OwnershipMessage = `${address}:${new Date().getTime().toString().slice(0, -3)}:starRegistry`; //construct the message as explained, with the address + time + starRegistry
            resolve(OwnershipMessage);    
        });

You have an example of the result message in the screenshot above the code.

We then implemented the submitStar(address, message, signature, star) method, which allows users to register a new block with the star object in it into the chain. So formally notarize the new start using the address, the message, the signature and the star.

  /**
     * The submitStar(address, message, signature, star) method
     * will allow users to register a new Block with the star object
     * into the chain. This method will resolve with the Block added or
     * reject with an error.
     * Algorithm steps:
     * 1. Get the time from the message sent as a parameter example: `parseInt(message.split(':')[1])`
     * 2. Get the current time: `let currentTime = parseInt(new Date().getTime().toString().slice(0, -3));`
     * 3. Check if the time elapsed is less than 5 minutes
     * 4. Veify the message with wallet address and signature: `bitcoinMessage.verify(message, address, signature)`
     * 5. Create the block and add it to the chain
     * 6. Resolve with the block added.
     * @param {*} address 
     * @param {*} message 
     * @param {*} signature 
     * @param {*} star 
     */
    submitStar(address, message, signature, star) {
        let self = this;
        return new Promise(async (resolve, reject) => {
            let temps = parseInt(message.split(':')[1]);                              //Get the time from the message sent as a parameter
            let currentTime = parseInt(new Date().getTime().toString().slice(0, -3)); //Get the current time
            if (currentTime-temps < (5*60)){                                           //Check if the time elapsed is less than 5 minutes
                if(bitcoinMessage.verify(message, address, signature)) {              //If yes verify the message
                    let block = new BlockClass.Block({"owner":address, "star":star});  //creation of the new block with the owner and the star 
                    self._addBlock(block);                                            //Add the block
                    resolve(block);                                                   //Resolve with the new block
                }else{
                    reject(Error('Message is not verified'))                          //Error message
                }
            }else{
                reject(Error('too much time has passed, stay below 5 minutes'))       //Error message
            }
        });
    }

Note that we use the bitcoinMessage. verify method to check that the signature is valid. If the conditions are met we create the new block with the owner and the star and we add the block with the previously created addBlock method.

We then implemented getBlockByHash(hash) method, this methods returns a promise that will resolve the block with the hash passed as parameter, so basically find a block using the hash query.

    /**
     * This method will return a Promise that will resolve with the Block
     *  with the hash passed as a parameter.
     * Search on the chain array for the block that has the hash.
     * @param {*} hash 
     */
    getBlockByHash(hash) {
        let self = this;
        return new Promise((resolve, reject) => {
            const block = self.chain.filter(block => block.hash === hash);
            if (typeof block != 'undefined'){
                resolve(block); 
            }else{
                reject(Error("No block with this hash"))
            }          
        });
    }

This one is pretty easy, we use filter to get the block with the hash passed in argument. If we find a block with resolve it if not we throw an error

Alright next one is getStarsByWalletAddress(address), this one will resolve all the stars in an array that the address passed in parameter owns (is owner of).

    /**
     * This method will return a Promise that will resolve with an array of Stars objects existing in the chain 
     * and are belongs to the owner with the wallet address passed as parameter.
     * Remember the star should be returned decoded.
     * @param {*} address 
     */
     getStarsByWalletAddress(address) {
        let self = this;                            //get blockchain
        let stars = [];                             //create array of stars
        return new Promise((resolve, reject) => { 
             self.chain.forEach(async(b)=> {        //loop on the blocks 
              let data = await b.getBData();        //get decoded data from each block
              if(data){
                  if(data.owner === address){       //check if owner of the star is address passed in param
                    stars.push(data);               //if yes add star's data to stars array
                  }
              }
          })
         resolve(stars);                            //return array of stars
        });
    }

And finally we implement the validateChain() method, it will return a promise that will resolve with the list of errors when validating the chain :

   /**
     * This method will return a Promise that will resolve with the list of errors when validating the chain.
     * Steps to validate:
     * 1. You should validate each block using `validateBlock`
     * 2. Each Block should check the with the previousBlockHash
     */
     validateChain() {
        let self = this;
        let errorLog = [];
        return new Promise((resolve) => {
            // Go through each block and make sure stored hash of
            // previous block matches actual hash of previous block
            let validatePromises = [];
            self.chain.forEach((block, index) => {
                if (block.height > 0) {
                    const previousBlock = self.chain[index - 1];
                    if (block.previousBlockHash !== previousBlock.hash) {
                        const errorMessage = `Block ${index} previousBlockHash set to ${block.previousBlockHash}, but actual previous block hash was ${previousBlock.hash}`;
                        errorLog.push(errorMessage);
                    }
                }

                // Store promise to validate each block
                validatePromises.push(block.validate());
            });

            // Collect results of each block's validate call
            Promise.all(validatePromises)
                .then(validatedBlocks => {
                    validatedBlocks.forEach((valid, index) => {
                        if (!valid) {
                            const invalidBlock = self.chain[index];
                            const errorMessage = `Block ${index} hash (${invalidBlock.hash}) is invalid`;
                            errorLog.push(errorMessage);
                        }
                    });

                    resolve(errorLog);
                });
        });
    }

I had troubles with this one to be honest. But basically it compares the hash “previousblock” of each block with the actual previous block hash and we call the validate() method on each block to make sure that the hash has been properly calculated. If all hashes are fine and all blocks have the right previous block’s hash, then the chain is valid.

Last one, but not the lease, we are going to create an endpoint that was missing in the BlockchainController.js file:

    validateChainEP(){
    this.app.get("/validateChain", async(req, res) =>{
        let errorLog = await this.blockchain.validateChain();
        if(errorLog.length!=0){
            return res.status(500).send("Chain is wrong");
        }else{
            return res.status(200).send("All is good");
        }
    });
}

And don’t forget to add into the constructor 🙂

    //The constructor receive the instance of the express.js app and the Blockchain class
    constructor(app, blockchainObj) {
        this.app = app;
        this.blockchain = blockchainObj;
        // All the endpoints methods needs to be called in the constructor to initialize the route.
        this.getBlockByHeight();
        this.requestOwnership();
        this.submitStar();
        this.getBlockByHash();
        this.getStarsByOwner();
        this.validateChainEP(); //Here
    }

Finally, we are done with the code and we are going to test it. Node.js uses JavaScript on the server. So we are going basically to GET and POST throught the REST API and the endpoints. Alright, we start the application and then when it’s running we are going to create the “link” in POSTMAN. Get it from here : https://www.postman.com/downloads/

Postman is basically an app to interact with your APIs simply. You construct the server with node.js and you interact with your endpoints through Postman.

So, how do you do that ? You run postman and then you simply add new connections through the button :

And then it depends wether you want a GET or a POST, so basically if you want to retrieve data or if you want to post data.

If you still find it difficult, this video helped me grasp it : https://www.youtube.com/watch?v=ngA-sTqRFVw

Here are the ones I created and how they run :

Get the genesis block, notice “height/0”, if you change the 0 to 1 you will get the second block of the chain etc.. click on the send button and voila you should see in the body the block info

http://localhost:8000/block/height/0

Second one is a POST one, we input the { “address”:”XXX”} into the body section is JSON format and then we click send, the app will respond with the message to be signed :

http://localhost:8000/requestValidation
{
    "address":"1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN"
}

Next one is to submit a star, same it is a POST one, we input in the body in JSON format the required information and then we click on send and the app returns the new added block. address is your bitcoin wallet address, signature is the output of the signature service, the message is what was outputed in the previous call.

http://localhost:8000/submitstar
{
    "address":"1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN",
    "signature":"G8H2UhDCwiAeAg/IRvRAtJJ3yL3haZ3OpbNHoVPy9V9r2+lV1j7aogL3grojamoERH3/ThduzjFayS1bYIBpCx0=",
    "message":"1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN:1621033644:starRegistry",
    "star":{
        "dec":"68 52 56",
        "ra":"18h 28m 1.0s",
        "story":"Testing a useless star"
    }
}

Then we have the GET method where you paste the address and the app gives you all the stars owned by this address :

http://localhost:8000/blocks/1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN

And finally the last one which confirms if the chain is valid :

localhost:8000/validateChain

Beautiful ! Everything works and we are ready to submit.