<repo_name>deboshas/BlockChainUsingJavaScript<file_sep>/dev/transcation.ts
export class Transcation {
    Amount: number;
    sender: string;
    recepient: string;
}<file_sep>/dev/Block.ts
import { Transcation } from "./transcation";

export class Block {
    index: number;
    Hash: string;
    previousBlockHash: string;
    Transcations: Transcation[];
    TimeStamp: string;
    nance: number;

    constructor(hash, prevHash, Trasncationdata, nance) {

        this.Hash = hash;
        this.previousBlockHash = prevHash;
        this.nance = nance;
        this.TimeStamp = "9-9-";
        this.Transcations.push(Trasncationdata);
    }
}<file_sep>/dev/blockChain.js
const sha256 = require('sha256');
const currentNodeurl = process.argv[3];
const uuid = require('uuid/v1');//unique identifer for ths current node

class BlockChain {

    constructor() {

        this.chain = [];
        this.pendingTransactions = [];
        this.addBlocktoChain(this.createNewBlock(100, '0', '0'));//genesys block,first block
        this.currentNodeUrl = currentNodeurl;
        this.networkNodes = [];
        this.node_address = uuid().split('-').join('');
    }

    createNewBlock(nance, previousBlockHash, hash) {
        const newBlock = {
            index: this.chain.length + 1,
            timestamp: Date.now(),
            transactions: this.pendingTransactions,
            nance: nance,
            hash: hash,
            previousBlockHash: previousBlockHash
        };

        this.pendingTransactions = [];


        return newBlock;
    }

    addBlocktoChain(block) {
        this.chain.push(block);
    }


    getLastBlock() {
        return this.chain[this.chain.length - 1];
    }


    createNewTransaction(amount, sender, receiver) {

        //add a logic to validate the transcation before adding it to  pending transcation works
        const newTransaction = {
            amount: amount,
            sender: sender,
            receiver: receiver,
            transcationId: uuid().split('-').join('')
        };
        return newTransaction;

    }


    addTransactionToPendingTransactions(transactionObj) {

        this.pendingTransactions.push(transactionObj);

    }


    hashBlock(previousBlockHash, currentBlockData, nance) {
        const dataAsString = previousBlockHash + nance.toString() + JSON.stringify(currentBlockData);
        const hash = sha256(dataAsString);
        return hash;
    }


    proofOfWork(previousBlockHash, currentBlockData) {
        let nance = 0;
        let hash = this.hashBlock(previousBlockHash, currentBlockData, nance);
        while (hash.substring(0, 4) !== '0000') {
            nance++;
            hash = this.hashBlock(previousBlockHash, currentBlockData, nance);
        }

        return nance;
    }

    //need to fix it,return true in case of a block been  compromised
    ChainIsValid(blockChain) {
        let isValidChain = true;
        let isvalidGenesysBlock = true;
        let genesysBlock = blockChain.chain[0];
        //longest chain rule 
        //validate each an every block in current  node by comparing prev block hash with the  current block and also validating each and every data in the block by rehashing it
        for (var i = 1; i < blockChain.chain.length; i++) {
            let prevBlock = blockChain.chain[i - 1];
            let currentBlock = blockChain.chain[i];
            if (this.hashBlock(prevBlock.hash, { transcations: currentBlock.transactions, index: currentBlock.index }, currentBlock.nance).substring(0, 4) != '0000') {
                isValidChain = false;
                break;

            }
            if (prevBlock.hash != currentBlock.previousBlockHash) {
                isValidChain = false;
                break;
            }
        }
        //check for genesys block 
        if ((genesysBlock.nance != "100") || (genesysBlock.hash != "0") || (genesysBlock.previousBlockHash
            != "0") && (genesysBlock.transactions.length != 0)) {
            isvalidGenesysBlock = false
        }

        return isValidChain && isvalidGenesysBlock;
        //validate the data for evry block by re hashing


    }


}

module.exports = BlockChain<file_sep>/dev/networknode.js
const express = require('express');
const BlockChain = require('./blockChain');
const bodyParser = require('body-parser');
const port = process.argv[2];//port for different nodes
const url = process.argv[3];
const rp = require('request-promise');
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

const bitcoin = new BlockChain();

app.get('/blockchain', function (req, res) {

    res.send(bitcoin);

})

app.post('/transcation', function (req, res) {
    bitcoin.addTransactionToPendingTransactions(req.body.transcationData);
    res.json({ note: `Transcation will be added to  block at  ` });
})
//create a  new block for us  by mining
app.post('/mine', function (req, res) {
    registerNodePromises = [];
    const lastBlock = bitcoin.getLastBlock();
    const prevblockHash = lastBlock.hash;
    const currentBlockdata = {
        transcations: bitcoin.pendingTransactions,
        index: lastBlock.index + 1

    }
    let nance = bitcoin.proofOfWork(prevblockHash, currentBlockdata);

    let hash = bitcoin.hashBlock(prevblockHash, currentBlockdata, nance);


    let newBlock = bitcoin.createNewBlock(nance, prevblockHash, hash);
    //broad  cast the mined  block to teh enire network 

    bitcoin.networkNodes.forEach(networkNodeUrl => {
        let requestOptions = {
            url: networkNodeUrl + "/receive/new/block",
            method: 'Post',
            body: { block: newBlock },
            json: true

        }
        registerNodePromises.push(rp(requestOptions));
    });


    Promise.all(registerNodePromises)
        .then(data => {
            //add the block to chain if  teh block is accepted 
            bitcoin.addBlocktoChain(newBlock);
            //reward teh miner with a bitcoin
            let newTranscation = bitcoin.createNewTransaction(12.5, "mine-reward-programme", bitcoin.node_address);
            //broadcast the new reward  Tranascation to the entire network
            let requestOptions = {
                url: bitcoin.currentNodeUrl + "/transcation/broadcast",
                method: 'Post',
                body: {
                    transcationData: {
                        "amount": "12.5",
                        "sender": "mine reward programme",
                        "receiver": bitcoin.currentNodeUrl


                    }
                },
                json: true

            }
            return rp(requestOptions);




        })
        .then(data => {
            res.json({

                note: `New block mined successfully at ${newBlock.index}  and broadcasted successfully`,
                block: newBlock
            })

        })

    //reward this current node address with uuid unique id 




})

//create a decentrilized network--start
//register a node and broadcast it in the block chain network
app.post('/register-and-broadcast', function (req, res) {
    //new node wants to join our network

    const newNodeUrl = req.body.newNodeUrl;
    let registerNodePromises = [];

    //regsiter the new node  with self 

    if (bitcoin.networkNodes.indexOf(newNodeUrl) === -1) {
        bitcoin.networkNodes.push(newNodeUrl);
    }

    //broadcast the new node  to the  entire network 
    bitcoin.networkNodes.forEach(networkNodeUrl => {
        //hit register node endpoint for all nodes
        let requestOptions = {
            url: networkNodeUrl + "/register-node",
            method: 'Post',
            body: { newNodeUrl: newNodeUrl },
            json: true

        }
        registerNodePromises.push(rp(requestOptions));
    });
    Promise.all(registerNodePromises)
        .then(data => {
            //use the data 
            let bulkrequestOptions = {
                url: newNodeUrl + "/register-node-bulk",
                method: 'Post',
                body: { allnetworkNodes: [...bitcoin.networkNodes, bitcoin.currentNodeUrl] },
                json: true

            }

            return rp(bulkrequestOptions)

        }).then(data => {

            res.json({ note: "New Node registered successfully" });
        })

})

//register a node  to  the block chain network
app.post('/register-node', function (req, res) {

    if (bitcoin.networkNodes.indexOf(req.body.newNodeUrl) === -1 && req.body.newNodeUrl != bitcoin.currentNodeUrl) {
        bitcoin.networkNodes.push(req.body.newNodeUrl);
        res.json({ note: `New node is registerd successfully at ${bitcoin.currentNodeUrl} ` })
    }

    else {

        res.json({ note: `New node is already registred with ${bitcoin.currentNodeUrl} ` })
    }
})

//regsiter multiple nodes at once

app.post('/register-node-bulk', function (req, res) {


    let allnetworkNodes = req.body.allnetworkNodes;
    allnetworkNodes.forEach(url => {
        if (url != bitcoin.currentNodeUrl && bitcoin.networkNodes.indexOf(url) === -1) {
            bitcoin.networkNodes.push(url);
        }

    })
    res.json({ note: `New node is registerd with all the network nodes available` })

})

//create a decentrilized network--END

//sync the  nodes for transcation and mining --start
//this endpoint will be hit whenever we try to create a new transcsation
app.post('/transcation/broadcast', function (req, res) {

    let network_nodes = bitcoin.network_nodes;
    let transcationData = req.body.transcationData;
    let registerNodePromises = [];

    //create the  transcation in the current node

    let newTranscation = bitcoin.createNewTransaction(transcationData.amount, transcationData.sender, transcationData.receiver);
    bitcoin.addTransactionToPendingTransactions(newTranscation);


    //borad cast the  transcation to the enitre netwoprk
    bitcoin.networkNodes.forEach(networkNodeUrl => {
        let requestOptions = {
            url: networkNodeUrl + "/transcation",
            method: 'Post',
            body: { transcationData: newTranscation },
            json: true

        }
        registerNodePromises.push(rp(requestOptions));
    });


    Promise.all(registerNodePromises)
        .then(data => {

            res.json({ note: 'Transcation has benn boradcasted to every other node ' });
        });
});

app.post('/receive/new/block', function (req, res) {
    let newBlock = req.body.block;
    //validate teh new block upon receiving to check wheather teh block is legitimate or  not
    let lastBlock = bitcoin.getLastBlock();
    let correctHash = lastBlock.hash === newBlock.previousBlockHash;
    let correctindex = lastBlock.index === (newBlock.index - 1);
    if (correctHash && correctindex) {
        bitcoin.addBlocktoChain(newBlock);
        bitcoin.pendingTransactions = [];
        res.json({
            note: `New block is received and accepted and added to teh chain ${newBlock}`
        })

    }

    else {

        res.json({
            note: `New block is rejected by the  network  ${newBlock}`
        })

    }

})

app.get('/consensus', (req, res) => {

    registerNodePromises = [];
    bitcoin.networkNodes.forEach(networkNodeUrl => {
        let requestOptions = {
            url: networkNodeUrl + "/blockchain",
            method: 'Get',
            json: true

        }
        registerNodePromises.push(rp(requestOptions));
    });

    //longest chain rule implemenattion
    Promise.all(registerNodePromises)
        .then(blockChains => {

            blockChains.forEach(chain => {


            })
        });


})



//sync the  nodes for transcation and mining --End
app.listen(port, function () {
    console.log(`Listing on port ${port}`);
});

<file_sep>/dev/blockChainData.ts
import { Block } from "./Block";
import { Transcation } from "./transcation";
const sha256 = require('sha256');
const uuid = require('uuid/v1');//unique identifer for ths current node

export class BlockChain {

    Chain: Block[];
    CurrentNodeUrl: string;
    NetworkNodeUrls: string[]
    PendingTranscation: Transcation[];
    node_address: string;

    constructor() {

        this.node_address = uuid().spilt('-').join('');
    }

    createTranscation(amount, sender, receiver) {

        this.PendingTranscation.push({
            Amount: amount,
            sender: sender,
            recepient: receiver
        });
    }

    getLastBlockIndex() {

        return this.Chain.length - 1;
    }

    createBlock(hash, prevHash, nance) {
        //validate wheather  hash,previous and nance are empty before creating new block and  pushing  to chain
        let block = new Block(hash, prevHash, this.PendingTranscation, nance);
        block.index = this.Chain.length + 1;
        //push the block into chain/ledger
        this.Chain.push(block);

    }

    createHash(prevHash, currentData, nance) {
        //validate wheather  hash,previous and nance are empty before creating new block and  pushing  to chain
        let payload = prevHash + JSON.stringify(currentData) + nance;
        return sha256(payload);

    }
    //mine the block,after that only u can create the  block and and it to the chain
    proofOfWork(prevHash, currentData) {
        let nance = 0;
        let payload = prevHash + JSON.stringify(currentData) + nance;
        let hash: string = this.createHash(prevHash, currentData, nance);
        while (hash.substring(0, 4) != "0000") {
            nance++;
            payload = this.createHash(prevHash, currentData, nance);
            hash = sha256(payload);
        }

        return nance;

    }
}<file_sep>/dev/test.js
var BlockChain = require('./blockChain');
var bitcoin = new BlockChain();
let blockChaindata = {
    "chain": [
        {
            "index": 1,
            "timestamp": 1564544724877,
            "transactions": [

            ],
            "nance": 100,
            "hash": "0",
            "previousBlockHash": "0"
        },
        {
            "index": 2,
            "timestamp": 1564544819793,
            "transactions": [
                {
                    "amount": "10",
                    "sender": "tax",
                    "receiver": "public expenditure"
                },
                {
                    "amount": "10",
                    "sender": "1",
                    "receiver": "public expenditure"
                }
            ],
            "nance": 124840,
            "hash": "0000ec477f70dc528acdfc6fdd91ba5be2ca812ff3ee64cf439ae1ee0e51c7fb",
            "previousBlockHash": "0"
        },
        {
            "index": 3,
            "timestamp": 1564544841472,
            "transactions": [
                {
                    "amount": "12.5",
                    "sender": "mine reward programme",
                    "receiver": "http://localhost:3001",
                    "transcationId": "d9b3b7e0b34511e9b170897154018a7b"
                },
                {
                    "amount": "10",
                    "sender": "1",
                    "receiver": "public expenditure"
                },
                {
                    "amount": "10",
                    "sender": "1",
                    "receiver": "public expenditure"
                },
                {
                    "amount": "10",
                    "sender": "1",
                    "receiver": "public expenditure"
                }
            ],
            "nance": 86458,
            "hash": "0000e66932943be9a3aaa3fd672a560b5f7093d6f916ce2682c1090803e0f2d3",
            "previousBlockHash": "0000ec477f70dc528acdfc6fdd91ba5be2ca812ff3ee64cf439ae1ee0e51c7fb"
        },
        {
            "index": 4,
            "timestamp": 1564544891957,
            "transactions": [
                {
                    "amount": "12.5",
                    "sender": "mine reward programme",
                    "receiver": "http://localhost:3001",
                    "transcationId": "e69e9a60b34511e9b170897154018a7b"
                },
                {
                    "amount": "70",
                    "sender": "1",
                    "receiver": "public expenditure"
                },
                {
                    "amount": "90",
                    "sender": "1",
                    "receiver": "public expenditure"
                },
                {
                    "amount": "90",
                    "sender": "1",
                    "receiver": "public expenditure"
                }
            ],
            "nance": 473192,
            "hash": "00004bb91732d1930b3e8c064f44a44889145a7b6f3c116e4dc8dba5fe4cb52d",
            "previousBlockHash": "0000e66932943be9a3aaa3fd672a560b5f7093d6f916ce2682c1090803e0f2d3"
        },
        {
            "index": 5,
            "timestamp": 1564544903292,
            "transactions": [
                {
                    "amount": "12.5",
                    "sender": "mine reward programme",
                    "receiver": "http://localhost:3001",
                    "transcationId": "04b5b290b34611e9b170897154018a7b"
                }
            ],
            "nance": 22379,
            "hash": "00009e3237f5db39c5787ce1167e4a90ec635c419d7b5ae5c8800e816755d103",
            "previousBlockHash": "00004bb91732d1930b3e8c064f44a44889145a7b6f3c116e4dc8dba5fe4cb52d"
        },
        {
            "index": 6,
            "timestamp": 1564544909176,
            "transactions": [
                {
                    "amount": "12.5",
                    "sender": "mine reward programme",
                    "receiver": "http://localhost:3001",
                    "transcationId": "0b76d2d0b34611e9b170897154018a7b"
                }
            ],
            "nance": 2981,
            "hash": "0000677ccff4a72bafd5a0ced7cc456299d202b2ddb48266146bab88c7f9ddc4",
            "previousBlockHash": "00009e3237f5db39c5787ce1167e4a90ec635c419d7b5ae5c8800e816755d103"
        }
    ],
    "pendingTransactions": [
        {
            "amount": "12.5",
            "sender": "mine reward programme",
            "receiver": "http://localhost:3001",
            "transcationId": "0ef8cda0b34611e9b170897154018a7b"
        }
    ],
    "currentNodeUrl": "http://localhost:3001",
    "networkNodes": [

    ],
    "node_address": "a11edae0b34511e9b170897154018a7b"
};


console.log('validChain', bitcoin.ChainIsValid(blockChaindata));