In this tutorial, we’re gonna look at Blockchain concept and way to build a Blockchain using Javascript.
Next Post: How to create Blockchain API in Javascript
Contents
Blockchain Overview
In simplest term, a Blockchain is an immutable distributed ledger.
What is a ledger?
>> A ledger is simply a collection of financial accounts or transactions which records transactions that people have made.
How about ‘immutable’?
>> Immutable means that this ledger cannot be changed anyway. Once the transactions are recorded, they can never be undone or altered. Nobody can ever change the amount of money that was sent or which people took part in the transaction.
Last, ‘distributed’ means that this ledger is not controlled by a single entity.
>> Instead it is independently constructed and held by many nodes. For example, Bitcoin are supported and hosted by thousands of everyday computer across the whole world.
This is a great benefit of Blockchain technology because we don’t have to trust any single company with our data. Our data is persisted by the entire network of thousands of different entities which are all acting independently, and each entity has the exact same copy of the ledger which is hosted and synchronized across the entire network.
There are many ways that Blockchain technology can be applied to our world today to make certain industries more secure efficient and trustworthy such as financial services, healthcare, credit, energy…
Build a Blockchain
Setup environment
Install Nodejs
– install LTS version of Node from NodeJs Installer.
– verify you have everything installed correctly by command: npm --version
and node --version
.
Setup Project folder tree
Under Blockchain project folder, create src and test folder with blockchain.js file inside:
Initialize Nodejs runtime
Point command prompt to project folfer, run cmd:
npm init
Install SHA256 module
Run cmd:
npm install sha256
Now our Blockchain project structure is like this:
Block data structure
Block is the important part of our Blockchain. This is data structure of the item which will be connected in a chain inside our Blockchain later. All data that we need is stored inside Block objects.
class Block { constructor(index, timestamp, nonce, prevBlockHash, hash, transactions) { this.index = index; this.timestamp = timestamp; this.transactions = transactions; this.nonce = nonce; this.hash = hash; this.prevBlockHash = prevBlockHash; } } |
Block object has:
– index
property and this will be basically the block number in our chain.
– timestamp
that indicates when this block was created.
– transactions
: when we create a new block, we want to store all of the new transactions that have just been created. These transactions will be inside of block in a chain so that they can never be changed.
– nonce
: this is like a tiny info added to the contents of a block that makes hash output of the contents of the block will change. Miners must find a nonce value that, when put into the hashing algorithm, generates an output that meets the requirements, in this case, a certain number of leading zeros (for example, out must be start with 5-zeros: ‘00000fc87…e0’).
– hash
: a single string that all of our transactions and some info are going to be basically compressed into.
– prevBlockHash
: the hash
data from previous block.
Blockchain Object
Blockchain
class has ability to be instantiated, create new Block, access the latest Block information, make new Transaction, hash Block, run Proof Of Work, and has chain of Blocks along with pending Transactions that should be stored when new Block is created.
Constructor
class Blockchain { constructor() { this.chain = []; this.pendingTransactions = []; this.creatNewBlock(100, '0', 'Genesis block'); } } |
– chain
: this array is where all Blocks that we mine will be stored in as a chain.
– transactions
: where we will hold all of the new transactions that are created before they are placed into a new Block.
– We also create a Genesis Block in the constructor function.
So what is a Genesis Block?
>> Genesis Block is quite simply the first Block in a Blockchain. Every Blockchain needs to start with one block and we want this to happen right when the Blockchain is created.
The createNewBlock()
method has a nonce
, a prevBlockHash
and a hash
as parameters.
We don’t have any prevBlockHash
and we haven’t done any Proof Of Work. So to create this Block, we simply pass in some arbitrary parameters like below (or anything we like):
+ nonce
: 100
+ prevBlockHash
: ‘0’
+ hash
: ‘Genesis block’
Create new Block
class Blockchain { ... creatNewBlock(nonce, prevBlockHash, hash) { const newBlock = new Block( this.chain.length + 1, Date.now(), nonce, prevBlockHash, hash, this.pendingTransactions ); this.pendingTransactions = []; this.chain.push(newBlock); return newBlock; } } |
This method takes 3 parameters: nonce
, prevBlockHash
and hash
.
– First, we create a new Block object.
– Next, we set pendingTransactions
equal to an empty array. This is because once we create a new Block, we are putting all of the new transactions into this Block. Clearing the entire transactions array helps us start over for the next Block.
– Then we push new Block into our chain.
– Finally we return the new Block.
Get latest Block
class Blockchain { ... getLatestBlock() { return this.chain[this.chain.length - 1]; } } |
Make new Transaction
class Blockchain { ... makeNewTransaction(amount, sender, recipient) { const transaction = { amount: amount, sender: sender, recipient: recipient } this.pendingTransactions.push(transaction); console.log(`>>> Transaction: ${amount} from ${sender} to ${recipient}`); return this.getLatestBlock().index + 1; } } |
This method takes 3 parameters:
+ amount
: indicates how much is being sent in this transaction.
+ sender
: sender’s address.
+ recipient
: recipient’s address.
– First, we create a new transaction
object from these parameters.
– Next, we push this transaction
into our pendingtransactions
array.
Our Blockchain has a lot of people who are making a lot of different transactions.
Every time a new transaction is created, it’s going to be pushed into our new transactions
array.
But all of the transactions in this array are not really set in the ledger. They’re not really recorded into our Blockchain yet, it just happens when a new Block is created.
>> So all of these new transactions are just pending transactions and they have not been validated.
– Finally, we return the number of the Block that this transaction will be added to.
Hash Block
Inside of this method, we use SHA256 hashing to hash our Block data.
const sha256 = require('sha256'); class Blockchain { ... hashBlock(prevBlockHash, currentBlock, nonce) { const data = prevBlockHash + JSON.stringify(currentBlock) + nonce; const hash = sha256(data); return hash; } } |
Proof of Work
Proof of Work is a very important method essential to Blockchain technology. It is one of the reasons that Bitcoin and many other Blockchains are so secured.
So, what is Proof of Work?
If we take a look at our Blockchain, we can see that every Blockchain is pretty much a list of Blocks.
Every single Block has to be created and added to the chain. But it is not enough.
We want to make sure that every Block that is added to the chain is legitimate, it must have the correct transactions and the correct data inside. People could fake how much Bitcoin they have and essentially cause fraud and steal money from other people.
>> Proof of Work helps us do this.
Everytime we create a new Block, we first have to make sure that it is a legitimate block by mining it through Proof of Work.
proofOfWork()
method will take in the prevBlockHash
and the currentBlockData
.
From this data, it is going to try to generate a specific hash
.
class Blockchain { ... proofOfWork(prevBlockHash, currentBlockData) { let nonce = 0; let hash = this.hashBlock(prevBlockHash, currentBlockData, nonce); while (hash.substring(0, 2) !== '00') { nonce++; hash = this.hashBlock(prevBlockHash, currentBlockData, nonce); }; return nonce; } } |
This hash
, in our case, is going to be a hash that starts with 2 zeros ('00'
).
The hash that is generated from SHA256 is random. So how to make this posible?
>> The only way we can do is by running our hashBlock()
method many many times until we get a hash
that starts with 2 zeros.
Now, how does this proof of work method actually secure the black chain?
>> The reason that this proofOfWork()
method will secure our Blockchain is because in order to generate the correct hash
, we have to run hashBlock()
method many many times, and it is going to use a lot of computing power and energy.
On top of that, not only our hashBlock()
method take in the currentBlockData
, but it also takes in the prevBlockHash
. This means that all of the Blocks in our Blockchain are linked together by their data.
>> So if someone tries to go back and remine or recreate a Block that already exists, he will also have to remind and recreates every single Block that comes after the first one they recreated. This would take an incredible amount of calculations and energy. It is not feasible for a well-developed Blockchain.
Even if he can change all Blocks, it would require massive amounts of computing power to access every instance (or at least a 51% majority) of a the Blockchain and alter them all at the same time. The bigger your network is, the more secure Blockchain will be.
Run Blockchain
test.blockchain.js
const Blockchain = require('../src/blockchain'); function mine(blockChain) { console.log('>>> Mining............'); const latestBlock = blockChain.getLatestBlock(); const prevBlockHash = latestBlock.hash; const currentBlockData = { transactions: blockChain.pendingTransactions, index: latestBlock.index + 1 } const nonce = blockChain.proofOfWork(prevBlockHash, currentBlockData); const blockHash = blockChain.hashBlock(prevBlockHash, currentBlockData, nonce); // reward for mining blockChain.makeNewTransaction(1, '00000', 'miningNode'); console.log('>>> Create new Block:\n', blockChain.creatNewBlock(nonce, prevBlockHash, blockHash)); } const bitcoin = new Blockchain(); console.log('>>> Create new Blockchain:\n', bitcoin); bitcoin.makeNewTransaction(120, 'JACK', 'JASON'); mine(bitcoin); bitcoin.makeNewTransaction(1120, 'JACK', 'JASON'); bitcoin.makeNewTransaction(300, 'JASON', 'JACK'); bitcoin.makeNewTransaction(2700, 'JACK', 'JASON'); mine(bitcoin); console.log('>>> Current Blockchain Data:\n', bitcoin); |
Run cmd: node test/blockchain.js
.
Result in Console:
>>> Create new Blockchain: Blockchain { chain: [ Block { index: 1, timestamp: 1527651336286, transactions: [], nonce: 100, hash: 'Genesis block', prevBlockHash: '0' } ], pendingTransactions: [] } >>> Transaction: 120 from JACK to JASON >>> Mining............ >>> Transaction: 1 from 00000 to miningNode >>> Create new Block: Block { index: 2, timestamp: 1527651336298, transactions: [ { amount: 120, sender: 'JACK', recipient: 'JASON' }, { amount: 1, sender: '00000', recipient: 'miningNode' } ], nonce: 158, hash: '00fc872e1ec7592dc50432882f601d0a30805d40925760e2b4363d288bee0d1e', prevBlockHash: 'Genesis block' } >>> Transaction: 1120 from JACK to JASON >>> Transaction: 300 from JASON to JACK >>> Transaction: 2700 from JACK to JASON >>> Mining............ >>> Transaction: 1 from 00000 to miningNode >>> Create new Block: Block { index: 3, timestamp: 1527651336304, transactions: [ { amount: 1120, sender: 'JACK', recipient: 'JASON'}, { amount: 300, sender: 'JASON', recipient: 'JACK' }, { amount: 2700, sender: 'JACK', recipient: 'JASON'}, { amount: 1, sender: '00000', recipient: 'miningNode' } ], nonce: 114, hash: '004c9050ff88b37deafc039a0ec3c4212a5cadb4a51e57039b928b64edfcd82b', prevBlockHash: '00fc872e1ec7592dc50432882f601d0a30805d40925760e2b4363d288bee0d1e' } >>> Current Blockchain Data: Blockchain { chain: [ Block { index: 1, timestamp: 1527651336286, transactions: [], nonce: 100, hash: 'Genesis block', prevBlockHash: '0' }, Block { index: 2, timestamp: 1527651336298, transactions: [Array], nonce: 158, hash: '00fc872e1ec7592dc50432882f601d0a30805d40925760e2b4363d288bee0d1e', prevBlockHash: 'Genesis block' }, Block { index: 3, timestamp: 1527651336304, transactions: [Array], nonce: 114, hash: '004c9050ff88b37deafc039a0ec3c4212a5cadb4a51e57039b928b64edfcd82b', prevBlockHash: '00fc872e1ec7592dc50432882f601d0a30805d40925760e2b4363d288bee0d1e' } ], pendingTransactions: [] } |