Building a Blockchain Using JavaScript: Part 1

Building a Blockchain Using JavaScript: Part 1

In this article, we will dive into the world of blockchain technology and explore how to build a blockchain using JavaScript. We will start by introducing JavaScript classes and constructors, which are fundamental to the implementation of our blockchain. Then, we will dissect with code examples, explaining the reasoning behind each component and its role in our blockchain system.

JavaScript Classes and Constructors

JavaScript classes are a way to define blueprints for creating objects with similar properties and behaviors. They provide a clean and organized approach to building complex systems. Constructors, on the other hand, are special methods within a class that are used to initialize objects created from that class. They allow us to set initial values for the properties of the object.

Understanding the Blockchain:Blocks, Timestamps, Hashes, and Data

Blocks: Building the Foundation

At the core of a blockchain is the concept of blocks. A block is a container that holds a collection of data, representing a transaction or a piece of information. Each block is linked to the previous block, forming a chain of blocks, hence the name "blockchain."

A block typically consists of several key components:

  1. Index: The index represents the position of the block within the blockchain. It helps maintain the order and sequence of blocks.

  2. Timestamp: The timestamp records the exact time when the block is created or added to the blockchain. It provides a chronological reference for the blocks.

  3. Data: The data section of a block contains the actual information or transaction that the block represents. It can vary depending on the specific use case of the blockchain. For example, in a cryptocurrency blockchain, the data may include details about the sender, recipient, and amount of the transaction.

  4. Previous Hash: The previous hash is a unique identifier that points to the hash of the previous block in the blockchain. It establishes the link between blocks and ensures the integrity and immutability of the blockchain.

  5. Hash: The hash is a cryptographic function that takes the block's properties (index, timestamp, data, and previous hash) and produces a unique output. The hash serves as a digital fingerprint of the block, providing a way to verify the integrity of the data within the block.

Timestamps: Establishing Chronological Order

Timestamps play a crucial role in blockchain technology by establishing the chronological order of blocks. Each block is assigned a timestamp that records the exact time when the block is created or added to the blockchain. This timestamp ensures that the blocks are arranged in a sequential and time-stamped manner, enabling the blockchain to maintain an accurate and immutable record of transactions or information.

By using timestamps, blockchain systems can provide transparency and accountability, as the order of events can be easily verified and audited. Additionally, timestamps enable the detection of any attempts to tamper with the blockchain by comparing the recorded timestamps with external time references.

Hashes: Ensuring Security and Integrity

Hashes are a critical component of blockchain technology, providing security and ensuring the integrity of the data stored within blocks. A hash is a unique output generated by applying a cryptographic function to the properties of a block (index, timestamp, data, and previous hash).

The hash serves as a digital fingerprint of the block, uniquely identifying its contents. Even a small change in any of the block's properties will result in a completely different hash. This property makes it virtually impossible to alter the data within a block without changing the hash, thus ensuring the immutability and integrity of the blockchain.

Hashes also play a crucial role in establishing the link between blocks. The previous hash property of a block points to the hash of the previous block in the chain. This linkage creates a chain of blocks, where any modification to a block will result in a mismatch between the hashes, alerting the network to potential tampering attempts.

Chains of Blocks: Creating a Decentralized Ledger

The concept of chains of blocks forms the foundation of a blockchain. Each block in the chain contains a reference to the previous block's hash, creating a continuous and unbroken sequence of blocks. This chain structure ensures the integrity and immutability of the blockchain, as any modification to a block will result in a mismatch between the hashes, breaking the chain.

The chain of blocks serves as a decentralized ledger, recording and storing transactions or information in a transparent and secure manner. Each participant in the blockchain network has a copy of the entire chain, allowing for verification and consensus among the network participants.

By utilizing cryptographic functions, timestamps, and hashes, blockchain technology provides a robust and tamper-proof system for storing and verifying data. The decentralized nature of the blockchain ensures that no single entity has control over the entire system, making it resistant to censorship and manipulation.

Now that we have a basic understanding of JavaScript classes and constructors and the scope of blockchain itself let's get technical and start building

Building A Blockchain

Let's start by examining the Block class:

const { SHA256 } = require("crypto-js");

class Block {
  constructor(index, timestamp, data, previousHash = "") {
    this.index = index;
    this.timestamp = timestamp;
    this.data = data;
    this.previousHash = previousHash;
    this.hash = this.calculateHash();
  }
  calculateHash() {
    return SHA256(
      this.index +
        this.previousHash +
        this.timestamp +
        JSON.stringify(this.data)
    ).toString();
  }
}

The Block class represents individual blocks within the blockchain. Each block has several properties: index, timestamp, data, previousHash, and hash. The constructor method takes in these properties as arguments and initializes the object with the provided values. It also calculates the hash of the block using the calculateHash method.

The calculateHash method utilizes the SHA256 function from the crypto-js library to compute the hash of the block. It concatenates the block's properties and uses JSON.stringify to convert the block's data object into a string. This ensures that any changes to the data will result in a different hash.

Moving on, let's examine the Blockchain class:

class Blockchain {
  constructor() {
    this.chain = [this.createGenesisBlock()];
  }
  createGenesisBlock() {
    return new Block(0, "13/09/2023", "Genesis block", "0");
  }
  getLatestBlock() {
    return this.chain[this.chain.length - 1];
  }
  addBlock(newBlock) {
    newBlock.previousHash = this.getLatestBlock().hash;
    newBlock.hash = newBlock.calculateHash();
    this.chain.push(newBlock);
  }
  isChainValid() {
    for (let i = 1; i < this.chain.length; i++) {
      const currentBlock = this.chain[i];
      const previousBlock = this.chain[i - 1];
      if (currentBlock.hash !== currentBlock.calculateHash()) {
        return false;
      }
      if (currentBlock.previousHash !== previousBlock.hash) {
        return false;
      }
    }
    return true;
  }
}

The Blockchain class represents the entire blockchain system. It has a single property called chain, which holds an array of blocks. The constructor method initializes the blockchain by creating the genesis block using the createGenesisBlock method.

The createGenesisBlock method defines the properties of the first block, such as the index, timestamp, data, and previous hash. It sets the previous hash to "0" since there is no previous block. Then, it utilizes the Block class to create the genesis block.

The getLatestBlock method returns the last block in the blockchain by accessing the chain array and retrieving the element at the last index.

The addBlock method takes a new block as an argument and adds it to the blockchain. It sets the previous hash of the new block to the hash of the last block in the chain and then calculates the hash of the new block. Finally, it pushes the new block into the chain array.

The isChainValid method checks the validity of the blockchain. It iterates through each block in the chain, comparing the hash of each block with the calculated hash. Additionally, it ensures that the previous hash of each block matches the hash of the previous block.

Finally, let's see the code in action:

let ledger = new Blockchain();
ledger.addBlock(new Block(1, "13/09/2023", { amount: 4 }));
ledger.addBlock(new Block(2, "14/09/2023", { amount: 29 }));
console.log("Is blockchain valid? " + ledger.isChainValid());
ledger.chain[1].data = { amount: 700 };
ledger.chain[1].calculateHash();
console.log("Is blockchain valid? " + ledger.isChainValid());
console.log(JSON.stringify(ledger, null, 4));

Here, we create an instance of the Blockchain class called ledger. We then add two blocks to the ledger using the addBlock method, each with its own index, timestamp, and data. After adding the blocks, we check the validity of the blockchain using the isChainValid method and log the result.

To demonstrate the immutability of the blockchain, we attempt to modify the data of the second block by assigning a new value to ledger.chain[1].data. We then recalculate the hash of the modified block using ledger.chain[1].calculateHash(). Finally, we check the validity of the blockchain again and log the result.

Conclusion

In the next articles, we will delve deeper into the functionality of our blockchain, exploring concepts such as mining, consensus algorithms, and decentralized networks. Stay tuned for Part 2 of our series on building a blockchain using JavaScript.

You can find the complete code discussed in this article below:

const { SHA256 } = require("crypto-js");

class Block {
  constructor(index, timestamp, data, previousHash = "") {
    this.index = index;
    this.timestamp = timestamp;
    this.data = data;
    this.previousHash = previousHash;
    this.hash = this.calculateHash();
  }
  calculateHash() {
    return SHA256(
      this.index +
        this.previousHash +
        this.timestamp +
        JSON.stringify(this.data)
    ).toString();
  }
}
class Blockchain {
  constructor() {
    this.chain = [this.createGenesisBlock()];
  }
  createGenesisBlock() {
    return new Block(0, "13/09/2023", "Genesis block", "0");
  }
  getLatestBlock() {
    return this.chain[this.chain.length - 1];
  }
  addBlock(newBlock) {
    newBlock.previousHash = this.getLatestBlock().hash;
    newBlock.hash = newBlock.calculateHash();
    this.chain.push(newBlock);
  }
  isChainValid() {
    for (let i = 1; i < this.chain.length; i++) {
      const currentBlock = this.chain[i];
      const previousBlock = this.chain[i - 1];
      if (currentBlock.hash !== currentBlock.calculateHash()) {
        return false;
      }
      if (currentBlock.previousHash !== previousBlock.hash) {
        return false;
      }
    }
    return true;
  }
}

let ledger = new Blockchain();
ledger.addBlock(new Block(1, "13/09/2023", { amount: 4 }));
ledger.addBlock(new Block(2, "14/09/2023", { amount: 29 }));
console.log("Is blockchain valid? " + ledger.isChainValid());
ledger.chain[1].data = { amount: 700 };
ledger.chain[1].calculateHash();
console.log("Is blockchain valid? " + ledger.isChainValid());
console.log(JSON.stringify(ledger, null, 4));