A Minimal Cryptocurrency in Node.js
Blockchain’s appeal comes from its ability to secure trustless, decentralized systems. While Python has long been the go-to for blockchain development, Node.js is now a perfectly capable platform for building distributed-ledger prototypes. This walkthrough shows how to create a simple cryptocurrency called smashingCoin using JavaScript classes and Node.js.
Before writing code, it helps to understand the basic mechanics. A blockchain is a distributed public ledger made of blocks linked cryptographically. Each block holds transaction data, a timestamp, its own hash, a nonce (a random number used once), and the hash of the previous block. Because every block points to its predecessor, altering any block invalidates the entire chain — this is the core immutability property that underpins blockchain security.
Consensus protocols like proof of work add another security layer. Proof of work requires computational effort to add a new block, making spamming or tampering impractical. In most cryptocurrencies, miners solve a difficult mathematical problem, and the difficulty increases as the chain grows.
Building a Block
Start by creating the CryptoBlock class. It needs a constructor() to initialize its properties and a computeHash method to generate a unique identifier for each block.
const SHA256 = require('crypto-js/sha256');
class CryptoBlock{
constructor(index, timestamp, data, precedingHash=" "){
this.index = index;
this.timestamp = timestamp;
this.data = data;
this.precedingHash = precedingHash;
this.hash = this.computeHash();
}
computeHash(){
return SHA256(this.index + this.precedingHash + this.timestamp + JSON.stringify(this.data)).toString();
}
}
The constructor accepts the block’s index, timestamp, data, and precedingHash:
index | It’s a unique number that tracks the position of every block in the entire blockchain. |
timestamp | It keeps a record of the time of occurrence of each completed transaction. |
data | It provides data about the completed transactions, such as the sender details, recipient’s details, and quantity transacted. |
precedingHash | It points to the hash of the preceding block in the blockchain, something important in maintaining the blockchain’s integrity. |
The computeHash method uses the crypto-js library’s SHA256 module. Since the module returns a number object, the toString() method converts it to a string. Install the library with npm:
npm install --save crypto-js
This adds the library and its dependencies to your project’s node_modules directory.
Assembling the Chain
Next comes the CryptoBlockchain class, which manages the operations of the entire chain through several helper methods.
class CryptoBlockchain{
constructor(){
this.blockchain = [this.startGenesisBlock()];
}
startGenesisBlock(){
return new CryptoBlock(0, "01/01/2020", "Initial Block in the Chain", "0");
}
obtainLatestBlock(){
return this.blockchain[this.blockchain.length - 1];
}
addNewBlock(newBlock){
newBlock.precedingHash = this.obtainLatestBlock().hash;
newBlock.hash = newBlock.computeHash();
this.blockchain.push(newBlock);
}
}
The constructor() instantiates the blockchain as an array and calls startGenesisBlock() to create the initial block.
The genesis block is the first block ever created on a network. Since no block precedes it, it must be hardcoded — typically with an index of 0 — so subsequent blocks can reference it. The startGenesisBlock() method creates it using the CryptoBlock class with the required parameters.
To maintain chain integrity, obtainLatestBlock() retrieves the last block so the current block’s hash can properly point to it. The addNewBlock() method sets the new block’s previous hash to the latest block’s hash, then recalculates the new block’s hash (since the properties changed) before pushing it into the blockchain array.
This simplified approach skips the validation checks a production blockchain would require, but it demonstrates the underlying concepts clearly.
Testing the Prototype
With the code in place, create a new instance of CryptoBlockchain called smashingCoin and add two blocks with sample transaction data:
let smashingCoin = new CryptoBlockchain();
smashingCoin.addNewBlock(new CryptoBlock(1, "01/06/2020", {sender: "Iris Ljesnjanin", recipient: "Cosima Mielke", quantity: 50}));
smashingCoin.addNewBlock(new CryptoBlock(2, "01/07/2020", {sender: "Vitaly Friedman", recipient: "Ricardo Gimenes", quantity: 100}) );
console.log(JSON.stringify(smashingCoin, null, 4));
Running this code outputs an object containing a blockchain property — an array of all blocks. Each block correctly references the hash of the previous one:
Verifying Integrity
For the chain to be trustworthy, it must detect tampering. Add a checkChainValidity() method to the CryptoBlockchain class. It loops over the chain starting from the first non-genesis block, verifying that each block’s computed hash matches its stored hash. It also confirms that each block’s previous hash matches the prior block’s hash. If everything checks out, the method returns true; otherwise it returns false.
checkChainValidity(){
for(let i = 1; i < this.blockchain.length; i++){
const currentBlock = this.blockchain[i];
const precedingBlock= this.blockchain[i-1];
if(currentBlock.hash !== currentBlock.computeHash()){
return false;
}
if(currentBlock.precedingHash !== precedingBlock.hash)
return false;
}
return true;
}
Hashes are central to this verification. Any change to a block’s contents produces a completely different hash, making malicious modifications visible.
Adding Proof of Work
To strengthen smashingCoin against spam and easy block generation, add a proofOfWork() method to the CryptoBlock class. This algorithm requires each block’s hash to begin with a number of zeros equal to a specified difficulty level. A higher difficulty means more computational effort and time to mine new blocks. A random nonce value is added so rehashing can still satisfy the difficulty constraint.
proofOfWork(difficulty){
while(this.hash.substring(0, difficulty) !==Array(difficulty + 1).join("0")){
this.nonce++;
this.hash = this.computeHash();
}
}
Update computeHash() to include the nonce variable:
computeHash(){
return SHA256(this.index + this.precedingHash + this.timestamp + JSON.stringify(this.data)+this.nonce).toString();
}
Finally, integrate proof of work into the addNewBlock() method so every new block must meet the difficulty requirement:
addNewBlock(newBlock){
newBlock.precedingHash = this.obtainLatestBlock().hash;
//newBlock.hash = newBlock.computeHash();
newBlock.proofOfWork(this.difficulty);
this.blockchain.push(newBlock);
}
Complete Implementation
The full code for smashingCoin brings all the pieces together:
const SHA256 = require("crypto-js/sha256");
class CryptoBlock {
constructor(index, timestamp, data, precedingHash = " ") {
this.index = index;
this.timestamp = timestamp;
this.data = data;
this.precedingHash = precedingHash;
this.hash = this.computeHash();
this.nonce = 0;
}
computeHash() {
return SHA256(
this.index +
this.precedingHash +
this.timestamp +
JSON.stringify(this.data) +
this.nonce
).toString();
}
proofOfWork(difficulty) {
while (
this.hash.substring(0, difficulty) !== Array(difficulty + 1).join("0")
) {
this.nonce++;
this.hash = this.computeHash();
}
}
}
class CryptoBlockchain {
constructor() {
this.blockchain = [this.startGenesisBlock()];
this.difficulty = 4;
}
startGenesisBlock() {
return new CryptoBlock(0, "01/01/2020", "Initial Block in the Chain", "0");
}
obtainLatestBlock() {
return this.blockchain[this.blockchain.length - 1];
}
addNewBlock(newBlock) {
newBlock.precedingHash = this.obtainLatestBlock().hash;
//newBlock.hash = newBlock.computeHash();
newBlock.proofOfWork(this.difficulty);
this.blockchain.push(newBlock);
}
checkChainValidity() {
for (let i = 1; i < this.blockchain.length; i++) {
const currentBlock = this.blockchain[i];
const precedingBlock = this.blockchain[i - 1];
if (currentBlock.hash !== currentBlock.computeHash()) {
return false;
}
if (currentBlock.precedingHash !== precedingBlock.hash) return false;
}
return true;
}
}
let smashingCoin = new CryptoBlockchain();
console.log("smashingCoin mining in progress....");
smashingCoin.addNewBlock(
new CryptoBlock(1, "01/06/2020", {
sender: "Iris Ljesnjanin",
recipient: "Cosima Mielke",
quantity: 50
})
);
smashingCoin.addNewBlock(
new CryptoBlock(2, "01/07/2020", {
sender: "Vitaly Friedman",
recipient: "Ricardo Gimenes",
quantity: 100
})
);
console.log(JSON.stringify(smashingCoin, null, 4));
Running it shows that each hash now begins with four zeros, matching the proof-of-work difficulty level:
smashingCoin cryptocurrency! (Large preview)This implementation demonstrates the essential building blocks of a cryptocurrency: custom block structures, a chained ledger, integrity verification, and a proof-of-work mechanism.
Where smashingCoin Falls Short
The implementation you have built is functional as a demonstration, but it is not production-ready. For example, there is no real peer-to-peer networking: the blockchain runs on a single node, meaning no decentralized consensus exists. A single user with write access controls the entire ledger, which defeats the purpose of a distributed system.
Neither proof-of-work difficulty adjustment nor a proper incentive mechanism is included. In a real cryptocurrency, miners need economic rewards and the network must adapt its hashing difficulty to ensure a consistent block time as computational power changes. Without these, the chain is vulnerable to spam and centralization.
There is also no transaction validation or balance tracking. The newTransaction method simply appends data, but the chain never verifies that a sender has sufficient funds or that a signature is authentic. For an actual currency, you would need cryptographic key pairs, transaction signing, and a UTXO model or account-based state machine.
Finally, the in-memory storage means everything is lost when you restart the server. Real systems require a database or file-based persistence layer.
Closing Thoughts
This tutorial gives you a minimal skeleton upon which to study more advanced blockchain concepts: consensus algorithms, transaction pools, merkle trees, and smart contract execution. You can extend this codebase by adding a proof-of-work timer, a GET route to query the full chain from your Node.js server, or a mechanism to broadcast new blocks to peers.
The sha256 hashing and the genesis-block pattern you implemented are the same fundamentals used in Bitcoin. If you want to go deeper, the resources below will help you explore the theory and next steps in building a distributed ledger that others might actually use.
References
- “Blockchain 101,” CoinDesk — a beginner's guide to how distributed ledgers work.
- “Bitcoin: A Peer-to-Peer Electronic Cash System,” Satoshi Nakamoto — the original whitepaper outlining the core design principles.
Further Reading
- How To Build A Node.js API For Ethereum Blockchain
- The Safest Way To Hide Your API Keys When Using React




