Blockchain is all the buzz now. And for good reason! A distributed public ledger that is extremely secure through encryption?! Imagine the millions of applicable use cases. A blockchain can be created and maintained using any modern language.
For the purpose of this blog, let’s dive into a blockchain written in JavaScript. Hopefully, this doesn’t just serve as a simple code example but also gives a very basic understanding of how a blockchain actually works.
Let’s first create a block and give it some attributes.
BlockIndex
– the position of the block on the blockchain.BlockCreatedWhen
– when the block was created.BlockTransaction
– a type of data to be stored on the block. This could be any exchange of value really. Perhaps an array of sorts.BlockPreviousHash
– hash of the previous block. This ties one block to another.Hash
– calculated hash function using the properties of the block. This is the block identifier on the blockchain. There is currently no built-in functionality for hash functions outside of the WebCryptoAPI. But there are plenty of other external libraries such as object-hash, crypto-hs, SJCL, forge SHA-256, etc.Nonce
– Proof of workMerkle Root
– A Merkle Root hash that houses all hashed transactions tied to a particular block.const hash = require('crypto-js/sha256'); // could also use object-hash, Stanford Javascript Crypto Library (SJCL), forge SHA-256, jsSHA, etc
class VincentsBlock{
constructor(blockIndex, blockCreatedWhen, blockTransactions, blockPreviousHash) {
this.blockIndex = blockIndex;
this.blockCreatedWhen = blockCreatedWhen;
this.blockTransactions = blockTransactions; // an array of transactions
this.blockPreviousHash = blockPreviousHash;
this.hash = this.calculateBlockHash();
this.nonce = 0; // needed for proof of work
this.merkleRoot = this.computeMerkleRoot() // used to validate transactions within block
}
calculateBlockHash() {
return hash(this.blockIndex + JSON.stringify(this.blockTransaction) + this.blockPreviousHash + this.blockCreatedWhen + this.nonce + this.merkleTreeRoot).toString();
}
computeMerkleRoot() {
let treeList = this.generateMerkleTreeRoot();
return treeList[treeList.length-1];
}
generateMerkleTreeRoot() {
let tree = [];
let transactionCount = this.blockTransactions.length;
for (var i=0; i<transactionCount; i++) { tree.push(this.blockTransactions[i].hash); } let levelOffset = 0; for (let levelSize = transactionCount; levelSize > 1; levelSize = (levelSize + 1) / 2) {
for (let left = 0; left < levelSize; left += 2) {
let right = Math.min(left + 1, levelSize - 1);
let tleft = tree[levelOffset + left];
let tright = tree[levelOffset + right];
tree.push(hash(tleft + tright));
}
levelOffset += levelSize;
}
return tree;
}
}
module.exports = VincentsBlock;
Notice the Merkle Root property on the block. Given that a transaction has its own hash generated, we can create a Merkle Tree out of the transaction list. This tree can then be used to validate the block transactions. Now that a block is generated, let’s go back and look at a transaction object. This should illustrate that a transaction can be anything really. This is where the many applications of blockchain come into play.
These particular transactions consist of a
I created a block transaction object as follows:
const hash = require('crypto-js/sha256');
class VincentsTransaction{
constructor(transactionId, inputAccount, outputAccount, fee, amount, type, misc, timestamp) {
this.transactionId = transactionId, // could be hex address
this.inputAccount = inputAccount; // sender
this.outputAccount = outputAccount; // receiver
this.fee = fee; // fee of transaction
this.amount = amount; // amount of transaction processed
this.type = type; // type of transaction
this.misc = misc; // misc note text
this.timestamp = timestamp // timestamp of block
this.hash = this.calculateTransactionHash(); // hash of the transaction
}
calculateTransactionHash() {
return hash(this.transactionId + this.inputAccount + this.outputAccount + this.fee + this.amount + this.type + this.misc + this.timestamp).toString();
}
}
module.exports = VincentsTransaction;
Moving on to the good part, let’s take a look at a basic immutable blockchain using the above blocks.
Below, in the constructor, you will notice a manual creation of the first block. This is needed to get the ball rolling. Every chain needs a first link!
Let’s manually create it and give it an index of 0 to show its placement on the chain. Many functions can be added to this class to assist on tasks such as adding blocks, checking for an empty chain, grabbing the latest block, validation, etc.
The process of creating additional blocks can be a complex one involving tons of validation if needed. We must keep in mind to regenerate the hash if any other property changes on a block.
In regards to validation of the blockchain, for now, we will focus on blocks linked together. Since index 0 corresponds to the manually created first block, we can skip it and check the hash of corresponding linked blocks.
let VincentsBlock = require('./VincentsBlock');
class VincentsBlockChain {
constructor() {
this.chain = [this.createBrandNewBlock()];
//this.current_transactions = [];
}
createBrandNewBlock() {
return new VincentsBlock(0, "01/01/2019", "Initial Block", ""); //no hash needed here since this is a manual creation of the first block.
}
createAdditionalBlock(newBlock) {
///very simplistic... could have more validation in place here.
let previousBlock = this.getLatestBlock();
newBlock.index = previousBlock.index + 1;
newBlock.blockPreviousHash = this.getLatestBlock().hash;
newBlock.hash = newBlock.calculateBlockHash(); //need to regenerate hash if any properties in our block changes
this.chain.push(newBlock);
}
getLatestBlock() {
return this.chain.slice(-1)[0];
}
isEmpty() {
return this.chain.length == 0;
}
isBlockChainValid() {
for(let i = 1;i < this.chain.length; i++) {
const currentBlock = this.chain[i];
const previousBlock = this.chain[i - 1];
if (currentBlock.blockPreviousHash != previousBlock.hash) { // does our block match up to correct previous hash property?
return false;
}
if (currentBlock.hash != currentBlock.calculateBlockHash()) { // does the actual hash of the block match up to it's current hash property?
return false;
}
if (previousBlock.index + 1 !== currentBlock.index) { // do the indexes line up in order?
return false;
}
}
return true;
}
};
module.exports = VincentsBlockChain;
For this simplistic example, let’s create 10 blocks, each with multiple transactions, and add them to the chain.
let VincentsBlockChain = require( "./blockchain/VincentsBlockChain");
let VincentsBlock = require( "./blockchain/VincentsBlock");
let VincentsTransaction = require( "./blockchain/VincentsTransaction");
let blockChain = new VincentsBlockChain();
blockChain.createAdditionalBlock(new VincentsBlock(1, "01/02/2019", [new VincentsTransaction(123, "abcxyz", "xyzabc", 30, "btc"), new VincentsTransaction(999, "uyyuyy", "xxdzkj", 550, "btc"), new VincentsTransaction(653, "drerea", "kioolk", 70, "eth")]));
blockChain.createAdditionalBlock(new VincentsBlock(2, "01/03/2019", [new VincentsTransaction(234, "sfgfsd", "rrttyu", 50, "eth"), new VincentsTransaction(555, "iuiuii", "rrttyu", 50, "eth"), new VincentsTransaction(553, "hghghg", "ffgfff", 80, "eth")]));
blockChain.createAdditionalBlock(new VincentsBlock(3, "01/04/2019", [new VincentsTransaction(345, "srthhf", "oouyuu", 65, "btc"), new VincentsTransaction(452, "jhghgg", "rrttyu", 11, "eth"), new VincentsTransaction(230, "wewfgf", "ghjgtt", 230, "eth")]));
blockChain.createAdditionalBlock(new VincentsBlock(4, "01/05/2019", [new VincentsTransaction(456, "sfgfss", "xzsdee", 4, "btc"), new VincentsTransaction(780, "fgtfdd", "rrttyu", 22, "eth"), new VincentsTransaction(112, "qwewue", "hgyuyu", 280, "eth")]));
blockChain.createAdditionalBlock(new VincentsBlock(5, "01/06/2019", [new VincentsTransaction(567, "xxcbbf", "nbvbcx", 545, "eth"), new VincentsTransaction(677, "fdfsaa", "uytttt", 33, "eth"), new VincentsTransaction(111, "hjhjh", "huiuii", 5480, "eth")]));
blockChain.createAdditionalBlock(new VincentsBlock(6, "01/07/2019", [new VincentsTransaction(678, "uiyuyy", "dfgree", 5, "btc"), new VincentsTransaction(553, "ooouio", "yuyuuu", 55, "eth"), new VincentsTransaction(467, "eeeewq", "jgftft", 880, "eth")]));
blockChain.createAdditionalBlock(new VincentsBlock(7, "01/08/2019", [new VincentsTransaction(789, "iughff", "opoiii", 125, "btc"), new VincentsTransaction(988, "aqQQQQ", "trewew", 01, "eth"), new VincentsTransaction(432, "eeeee", "khuuuu", 40, "eth")]));
blockChain.createAdditionalBlock(new VincentsBlock(8, "01/09/2019", [new VincentsTransaction(890, "sdsrer", "sdfser", 99, "eth"), new VincentsTransaction(886, "gfgfdg", "qqqqqq", 88, "eth"), new VincentsTransaction(444, "gfgfd", "llllkl", 70, "eth")]));
blockChain.createAdditionalBlock(new VincentsBlock(9, "01/10/2019", [new VincentsTransaction(901, "mnghjy", "dfgxbg", 65, "btc"), new VincentsTransaction(644, "dddsds", "wwwwww", 55, "eth"), new VincentsTransaction(333, "sdsaqq", "ererew", 50, "eth")]));
blockChain.createAdditionalBlock(new VincentsBlock(10, "01/11/2019", [new VincentsTransaction(012, "vccvff", "uiyfvv", 74, "btc"), new VincentsTransaction(994, "mnmnmm", "qqqqhh", 66, "eth"), new VincentsTransaction(323, "qwqwqq", "wreret", 30, "eth")]));
console.log(JSON.stringify(blockChain, null, 2)); // let's view entire blockchain
console.log('Validate entire blockchain: ' + blockChain.isBlockChainValid()); // let's validate the blockchain is secure
blockChain.chain[5].hash = blockChain.chain[5].calculateBlockHash(); // let's try to recalculate hash for block 5
console.log('Is blockchain valid? ' + blockChain.isBlockChainValid());
Alright, let’s run this bad boy and see the blockchain we created.
{
"chain": [
{
"blockIndex": 0,
"blockCreatedWhen": "01/01/2019",
"blockTransactions": "Initial Block",
"blockPreviousHash": "",
"hash": "46d4d81e6047cccb6e856a4bc800ed344fbe4b78df5f5a7fe5862e8773cd022a",
"nonce": 0,
"merkleTreeRoot": {
"words": [
-474954686,
-1728308204,
-1694763832,
-1720731356,
665731556,
1687917388,
-1533699813,
2018687061
],
"sigBytes": 32
}
},
{
"blockIndex": 1,
"blockCreatedWhen": "01/02/2019",
"blockTransactions": [
{
"transactionId": 123,
"inputAccount": "abcxyz",
"outputAccount": "xyzabc",
"fee": 30,
"amount": "btc",
"hash": "324cc491e4436b69299a905847124308c6dfc272642d9dbb3808bd79048bc110"
},
{
"transactionId": 999,
"inputAccount": "uyyuyy",
"outputAccount": "xxdzkj",
"fee": 550,
"amount": "btc",
"hash": "3beef24348997907eaa0263d3eb1393b1e74cb365e730649c60a910ecbbee0d5"
},
{
"transactionId": 653,
"inputAccount": "drerea",
"outputAccount": "kioolk",
"fee": 70,
"amount": "eth",
"hash": "a30e34266150f7b616aa4ebe88461406308280c9821425dbe0bfbc1fa7e6843a"
}
],
"blockPreviousHash": "46d4d81e6047cccb6e856a4bc800ed344fbe4b78df5f5a7fe5862e8773cd022a",
"hash": "54ee7657f991b1341ecfa7d2ecfe7cf0501751f147ecc7b9ca08b2354068eeab",
"nonce": 0,
"merkleTreeRoot": {
"words": [
-474954686,
-1728308204,
-1694763832,
-1720731356,
665731556,
1687917388,
-1533699813,
2018687061
],
"sigBytes": 32
},
"index": null
},
{
"blockIndex": 2,
"blockCreatedWhen": "01/03/2019",
"blockTransactions": [
{
"transactionId": 234,
"inputAccount": "sfgfsd",
"outputAccount": "rrttyu",
"fee": 50,
"amount": "eth",
"hash": "f2378fced4de261dc5c531441d867b385f5726b76eb76d6ece8b739de3f6d2f7"
},
{
"transactionId": 555,
"inputAccount": "iuiuii",
"outputAccount": "rrttyu",
"fee": 50,
"amount": "eth",
"hash": "cb42ae591f275f7d265f749489c0830ef985252d256ad176430a9acee0b7c525"
},
{
"transactionId": 553,
"inputAccount": "hghghg",
"outputAccount": "ffgfff",
"fee": 80,
"amount": "eth",
"hash": "edb71da69f72d01fdefe7939665d8fc59489bb16e5f3d7e662a187b1d437ef8f"
}
],
"blockPreviousHash": "54ee7657f991b1341ecfa7d2ecfe7cf0501751f147ecc7b9ca08b2354068eeab",
"hash": "f58b63c0fbe00f69b6b1bd04560ffdd72ebe7b71e70a16224bf45aad01308e0f",
"nonce": 0,
"merkleTreeRoot": {
"words": [
-474954686,
-1728308204,
-1694763832,
-1720731356,
665731556,
1687917388,
-1533699813,
2018687061
],
"sigBytes": 32
},
"index": null
},
{
"blockIndex": 3,
"blockCreatedWhen": "01/04/2019",
"blockTransactions": [
{
"transactionId": 345,
"inputAccount": "srthhf",
"outputAccount": "oouyuu",
"fee": 65,
"amount": "btc",
"hash": "eaa995a8b3a64237c3133fbb744ed1761ba716781b7026f7f956043173c452f6"
},
{
"transactionId": 452,
"inputAccount": "jhghgg",
"outputAccount": "rrttyu",
"fee": 11,
"amount": "eth",
"hash": "e867bcef38e0272776fc3fbeff0aac19cb366ca513945ddfa1491adc2f3257b2"
},
{
"transactionId": 230,
"inputAccount": "wewfgf",
"outputAccount": "ghjgtt",
"fee": 230,
"amount": "eth",
"hash": "d25b62651513ee902e063970b5b7baed30de4f9832b7a78db3247a09414a1495"
}
],
"blockPreviousHash": "f58b63c0fbe00f69b6b1bd04560ffdd72ebe7b71e70a16224bf45aad01308e0f",
"hash": "288b9f37d503b22a5f4535e086ab84fdbff2e22f8880fb2f24baa29b5151235d",
"nonce": 0,
"merkleTreeRoot": {
"words": [
-474954686,
-1728308204,
-1694763832,
-1720731356,
665731556,
1687917388,
-1533699813,
2018687061
],
"sigBytes": 32
},
"index": null
},
{
"blockIndex": 4,
"blockCreatedWhen": "01/05/2019",
"blockTransactions": [
{
"transactionId": 456,
"inputAccount": "sfgfss",
"outputAccount": "xzsdee",
"fee": 4,
"amount": "btc",
"hash": "af15f83e9c599347351019f62309fb1b9077447a4e0fc8b48a6b5c487b1e144e"
},
{
"transactionId": 780,
"inputAccount": "fgtfdd",
"outputAccount": "rrttyu",
"fee": 22,
"amount": "eth",
"hash": "8984871129b02f0b09f83abd5c1161f6a0dee64f84c336a54f5c34e5454f02a7"
},
{
"transactionId": 112,
"inputAccount": "qwewue",
"outputAccount": "hgyuyu",
"fee": 280,
"amount": "eth",
"hash": "2631aa030dfbc44fe084d86f69c1d24ca64a154c59d13b42718211ed02e3b1dc"
}
],
"blockPreviousHash": "288b9f37d503b22a5f4535e086ab84fdbff2e22f8880fb2f24baa29b5151235d",
"hash": "07205c43afea9e53d02dedce994c891babccd8397d082b431f986045cbc18e44",
"nonce": 0,
"merkleTreeRoot": {
"words": [
-474954686,
-1728308204,
-1694763832,
-1720731356,
665731556,
1687917388,
-1533699813,
2018687061
],
"sigBytes": 32
},
"index": null
},
{
"blockIndex": 5,
"blockCreatedWhen": "01/06/2019",
"blockTransactions": [
{
"transactionId": 567,
"inputAccount": "xxcbbf",
"outputAccount": "nbvbcx",
"fee": 545,
"amount": "eth",
"hash": "8030161e3fdb7038fb7e751236063996152897f9647c654fb47334da7f7295bb"
},
{
"transactionId": 677,
"inputAccount": "fdfsaa",
"outputAccount": "uytttt",
"fee": 33,
"amount": "eth",
"hash": "b327dfa8769ec04bc447313af98feeb783c95c198e926737ea916700f4b71994"
},
{
"transactionId": 111,
"inputAccount": "hjhjh",
"outputAccount": "huiuii",
"fee": 5480,
"amount": "eth",
"hash": "aae165434e054c42e7da129b08a7c99f6c544351b7383459e322ef253570f4a4"
}
],
"blockPreviousHash": "07205c43afea9e53d02dedce994c891babccd8397d082b431f986045cbc18e44",
"hash": "55c88c98e497a9f300ca3ec8bec0129652a8e5e9b49e6ecaf4ab0c63b42ebf4f",
"nonce": 0,
"merkleTreeRoot": {
"words": [
-474954686,
-1728308204,
-1694763832,
-1720731356,
665731556,
1687917388,
-1533699813,
2018687061
],
"sigBytes": 32
},
"index": null
},
{
"blockIndex": 6,
"blockCreatedWhen": "01/07/2019",
"blockTransactions": [
{
"transactionId": 678,
"inputAccount": "uiyuyy",
"outputAccount": "dfgree",
"fee": 5,
"amount": "btc",
"hash": "134269524a221afb1f5ef218584b063ab4bea3aaa5dc2cdbfa66f439f2d1e36b"
},
{
"transactionId": 553,
"inputAccount": "ooouio",
"outputAccount": "yuyuuu",
"fee": 55,
"amount": "eth",
"hash": "19076e1cb35d8357b16f92794c5bd1ff020c8cb9e8ce5fcf03b560256a363c16"
},
{
"transactionId": 467,
"inputAccount": "eeeewq",
"outputAccount": "jgftft",
"fee": 880,
"amount": "eth",
"hash": "461ad65962d2d1cc1f767c1b9c0f569d19ef48be60ef2fe8c08898cc01d34492"
}
],
"blockPreviousHash": "55c88c98e497a9f300ca3ec8bec0129652a8e5e9b49e6ecaf4ab0c63b42ebf4f",
"hash": "e1087468c2719f967584cab0a22938b81e9e956762f2c5a2d2dd91da2c92cfbd",
"nonce": 0,
"merkleTreeRoot": {
"words": [
-474954686,
-1728308204,
-1694763832,
-1720731356,
665731556,
1687917388,
-1533699813,
2018687061
],
"sigBytes": 32
},
"index": null
},
{
"blockIndex": 7,
"blockCreatedWhen": "01/08/2019",
"blockTransactions": [
{
"transactionId": 789,
"inputAccount": "iughff",
"outputAccount": "opoiii",
"fee": 125,
"amount": "btc",
"hash": "7149930eae17b35f22c02acb0765b829d79e5539c6e2e80b837045f89d0422c2"
},
{
"transactionId": 988,
"inputAccount": "aqQQQQ",
"outputAccount": "trewew",
"fee": 1,
"amount": "eth",
"hash": "d752f91eb8010b5c9d6066afb92a5fa6c4667f9fc18b6f8d4a7c1a32b104919c"
},
{
"transactionId": 432,
"inputAccount": "eeeee",
"outputAccount": "khuuuu",
"fee": 40,
"amount": "eth",
"hash": "c5c20ac19253cd6782f0a95eb628c719cafeac22d4c8bacbf2863b06e0e366db"
}
],
"blockPreviousHash": "e1087468c2719f967584cab0a22938b81e9e956762f2c5a2d2dd91da2c92cfbd",
"hash": "63302ff671cee7c659e1bf9eb1cd659f054d4615c4692d5b425ad04b2f82deb6",
"nonce": 0,
"merkleTreeRoot": {
"words": [
-474954686,
-1728308204,
-1694763832,
-1720731356,
665731556,
1687917388,
-1533699813,
2018687061
],
"sigBytes": 32
},
"index": null
},
{
"blockIndex": 8,
"blockCreatedWhen": "01/09/2019",
"blockTransactions": [
{
"transactionId": 890,
"inputAccount": "sdsrer",
"outputAccount": "sdfser",
"fee": 99,
"amount": "eth",
"hash": "c4abc25fcc9ea1e78be488aac5ee9a3ee1f16b0915e23700ff6bb11e1df02c51"
},
{
"transactionId": 886,
"inputAccount": "gfgfdg",
"outputAccount": "qqqqqq",
"fee": 88,
"amount": "eth",
"hash": "fd454dbdfb263db527ed335116aab73a7dab8468d3d443aa0fd8e4c7e438f465"
},
{
"transactionId": 444,
"inputAccount": "gfgfd",
"outputAccount": "llllkl",
"fee": 70,
"amount": "eth",
"hash": "c9b9ebdcb469f0f5ae8c6653c10f45d88a59b807c87b9febe1be986844d558f4"
}
],
"blockPreviousHash": "63302ff671cee7c659e1bf9eb1cd659f054d4615c4692d5b425ad04b2f82deb6",
"hash": "fec255eb642f1dd02ab7c5185bfd78f9574b50c0188a888b4227b8cef5497e0e",
"nonce": 0,
"merkleTreeRoot": {
"words": [
-474954686,
-1728308204,
-1694763832,
-1720731356,
665731556,
1687917388,
-1533699813,
2018687061
],
"sigBytes": 32
},
"index": null
},
{
"blockIndex": 9,
"blockCreatedWhen": "01/10/2019",
"blockTransactions": [
{
"transactionId": 901,
"inputAccount": "mnghjy",
"outputAccount": "dfgxbg",
"fee": 65,
"amount": "btc",
"hash": "6e94502eb38d14410141d87bd27a2369e14e62bf8efece8adbde9873a8e88777"
},
{
"transactionId": 644,
"inputAccount": "dddsds",
"outputAccount": "wwwwww",
"fee": 55,
"amount": "eth",
"hash": "7072d7ec51bf41a1f36744f7abf8e9e4f70d195b708420f77b5141bcb7567f45"
},
{
"transactionId": 333,
"inputAccount": "sdsaqq",
"outputAccount": "ererew",
"fee": 50,
"amount": "eth",
"hash": "199c710224da1e16f597c2eae088acd5c3d4b6fd9a12d84c0b76a735eed541a2"
}
],
"blockPreviousHash": "fec255eb642f1dd02ab7c5185bfd78f9574b50c0188a888b4227b8cef5497e0e",
"hash": "fcec05a7f1afb3c91ddbf90f36e04d17e4eabd7e47545a9f08173767cd4d74c8",
"nonce": 0,
"merkleTreeRoot": {
"words": [
-474954686,
-1728308204,
-1694763832,
-1720731356,
665731556,
1687917388,
-1533699813,
2018687061
],
"sigBytes": 32
},
"index": null
},
{
"blockIndex": 10,
"blockCreatedWhen": "01/11/2019",
"blockTransactions": [
{
"transactionId": 10,
"inputAccount": "vccvff",
"outputAccount": "uiyfvv",
"fee": 74,
"amount": "btc",
"hash": "8f2abd539ef073b7d4053fe6090196f682f6361a619329e45a3a0df10919623c"
},
{
"transactionId": 994,
"inputAccount": "mnmnmm",
"outputAccount": "qqqqhh",
"fee": 66,
"amount": "eth",
"hash": "040dda42beee5673e882884e3e963292015253348b1db5c3feb5d54af4e4b728"
},
{
"transactionId": 323,
"inputAccount": "qwqwqq",
"outputAccount": "wreret",
"fee": 30,
"amount": "eth",
"hash": "af54b136d57904e80823c53649d4149092fb6ebb4bf1e8578facaae8aca2cf1c"
}
],
"blockPreviousHash": "fcec05a7f1afb3c91ddbf90f36e04d17e4eabd7e47545a9f08173767cd4d74c8",
"hash": "9074846c6a4153802d86cd19b6d95266c56d082329c6f0f52ded270fae269c48",
"nonce": 0,
"merkleTreeRoot": {
"words": [
-474954686,
-1728308204,
-1694763832,
-1720731356,
665731556,
1687917388,
-1533699813,
2018687061
],
"sigBytes": 32
},
"index": null
}
]
}
NOTE: Within the merkleTreeRoot property, crypto-js utilizes word arrays encoded as UTF-8 when given a string.
Above, notice the hash and blockPreviousHash
property of each block. This serves as the link for the chain.
But what happens if one were to modify a block somehow? Perhaps change the fee property or attempt to recalculate a block hash?
console.log('Validate entire blockchain: ' + blockChain.isBlockChainValid()); // let's validate the blockchain is secure
blockChain.chain[5].hash = blockChain.chain[5].generateBlockHash(); // let's try to recalculate hash for block 5
console.log('Is blockchain valid? ' + blockChain.isBlockChainValid());
Validate entire blockchain: true
Is blockchain valid? false
It appears that the blockchain validation function isBlockChainValid()
caught an attempt to recalculate its hash. Of course, this is pretty basic validation, but it serves its purpose to illustrate the secure nature of blockchain.
In summary, a blockchain can be written in various languages. I hope this basic JavaScript version not only illustrates that but gives a little more overview of how blockchains work.
Thank for reading ! Please share if you liked it!
#javascript #blockchain #bitcoin #altcoins #geek-cash